; Version 1.7.1

DEFINE:

InkColor EQU 0
PaperColor EQU 1
NoColorThemes EQU 4
CharGraphics EQU 0x3D00
TilemapBase EQU 0x4000
TileDefBase EQU 0x6000
TileDefSpace EQU 0x6400
TileDefEndHigh EQU 0x80
ObjectStartBank EQU 32
ObjectNoBanks EQU 4
VarsStartBank EQU 36
VarsNoBanks EQU 8
SourceStartBank EQU 44
SourceNoBanks EQU 52
SourceStartAddr EQU 0xC000
SourceLastAddr EQU 0xDFFF
SourceStartHigh EQU 0xC0
SourceEndHigh EQU 0xE0
SourceReserved0 EQU 0x0200
SourceReservedMin EQU 0x0100
SourceReservedMax EQU 0x0400
VarsStartAddr EQU 0xE000
VarsLastAddr EQU 0xFFFF
ObjectStartAddr EQU 0xE000
ObjectLastAddr EQU 0xFFFF
ObjectEndHigh EQU 0
CapsShift EQU 1
SymbolShift EQU 2
Extend EQU 14
CapsLeft EQU 16
CapsRight EQU 17
CapsDown EQU 18
CapsUp EQU 19
ExtendLeft EQU 20
ExtendRight EQU 21
SymbolLeft EQU 24
SymbolRight EQU 25
SymbolDown EQU 26
SymbolUp EQU 27
LineDelete EQU 28
CapsDownLines EQU 15
NoZ80Opcodes EQU 67
NoZ80N4Opcodes EQU 20
NoZ80N7Opcodes EQU 10
CroppedScreenFirstLine EQU 2
CroppedScreenLastLine EQU 29
NoCommands EQU 9

ErrorInvalidCommand EQU 1
ErrorMissingFileName EQU 2
ErrorInvalidFileName EQU 3
ErrorInvalidAddress EQU 4
ErrorSelectingFile EQU 5
ErrorMultidefOfVariable EQU 6
ErrorVariableNotFound EQU 7
ErrorSyntax EQU 8
ErrorArgumentMismatch EQU 9
ErrorOutOfMemory EQU 10
ErrorInvalidNumber EQU 11
ErrorTooManyCodeBlocks EQU 12
ErrorRelativeOutOfRange EQU 13
ErrorLoad EQU 14
ErrorSave EQU 15
ErrorORGExpected EQU 16
ErrorByteExpected EQU 17
ErrorInvalidArgument EQU 18
ErrorOverflowInExpression EQU 19
ErrorInvalidOperation EQU 20
ErrorDivisionByZero EQU 21
ErrorInvalidAssignment EQU 22
ErrorDebug EQU 23
ErrorInvalidENTRY EQU 24
ErrorWordExpected EQU 25

 ORG 0x8000

; initialize
 DI
 LD SP,0xC000
 NEXTREG 0x07,3
 CALL MemSetup
 CALL SetPalette
 CALL SetupTilemap
 CALL ClearScreen
 CALL SetupScreen
 CALL ClearSourceBank
 XOR A
 LD (SearchString),A

; initialize command line edit
CommandLineEdit:
 LD A,(LastLineOfScreen)
 LD B,A
 CALL ClearLine
 XOR A
 LD (CursorX),A
 LD (NoCharsInLine),A
 LD (LineBuffer),A
 LD (ModeFlag),A
 LD C,A
 LD A,(LastLineOfScreen)
 LD B,A
 LD A,160
 CALL PrintChar
; New input in command line
CLEditSymbol:
 CALL InputChar
 CP 7
 JP Z,SourceCodeEdit
 CP 4
 JR NZ,CLCheckLeft
 CALL ToggleColorTheme
 JR CLEditSymbol
CLCheckLeft:
 CP 8
 JR NZ,CLCheckRight
 LD A,(CursorX)
 AND A
 JR Z,CLEditSymbol
 LD C,A
CLMoveCursorLeft:
 LD B,0
 LD HL,LineBuffer
 ADD HL,BC
 LD A,(LastLineOfScreen)
 LD B,A
 LD A,(NoCharsInLine)
 CP C
 LD A,32
 JR Z,CLMCLScreenUpdate
 LD A,(HL)
CLMCLScreenUpdate:
 PUSH HL
 PUSH BC
 CALL PrintChar
 POP BC
 POP HL
 DEC C
 LD A,C
 LD (CursorX),A
 DEC HL
 LD A,(HL)
 OR 128
 CALL PrintChar
 JR CLEditSymbol
CLCheckRight:
 CP 9
 JR NZ,CLCheckDelete
 LD A,(CursorX)
 LD C,A
 LD A,(NoCharsInLine)
 CP C
 JR Z,CLEditSymbol
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
 LD A,(LastLineOfScreen)
 LD B,A
 LD A,(HL)
 PUSH HL
 PUSH BC
 CALL PrintChar
 POP BC
 POP HL
 INC HL
 INC C
 LD A,C
 LD (CursorX),A
 LD E,A
 LD A,(NoCharsInLine)
 CP E
 LD A,160
 JR Z,CLRightPrintCursor
 LD A,(HL)
 OR 128
CLRightPrintCursor:
 CALL PrintChar
 JR CLEditSymbol
CLCheckDelete:
 CP 12
 JR NZ,CLCheckEnter
 LD A,(CursorX)
 AND A
 JP Z,CLEditSymbol
 LD C,A
 LD A,(NoCharsInLine)
 DEC A
 LD (NoCharsInLine),A
 INC A
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
 SUB C
 JR NZ,CLDeleteInline
 LD (HL),32
 DEC HL
 LD (HL),32
 JP CLMoveCursorLeft
CLDeleteInline:
 LD C,A
 PUSH HL
 POP DE
 DEC DE
 LDIR
 LD HL,LineBuffer
 LD A,(LastLineOfScreen)
 LD B,A
 LD A,(NoCharsInLine)
 PUSH HL
 CALL PrintStrN
 LD A,32
 CALL PrintChar
 POP HL
 LD A,(CursorX)
 DEC A
 LD (CursorX),A
 LD C,A
 LD B,0
 ADD HL,BC
 LD A,(LastLineOfScreen)
 LD B,A
 LD A,(HL)
 OR 128
 CALL PrintChar
 JP CLEditSymbol
CLCheckEnter:
 CP 13
 JP NZ,CLCheckPrintable
 LD A,(LastLineOfScreen)
 LD B,A
 CALL ClearLine
 LD C,0
 CALL CLParseSpaces
 JP C,CommandLineEdit
 CALL CLParseCommand
 JR NC,CLCheckCommand
CLCommandError:
 LD A,ErrorInvalidCommand
 CALL PrintError
 JP CommandLineEdit
CLCheckCommand:
 CP 2
 JP Z,CLFind
 CP 3
 JP Z,CLAssemble
 CP 4
 JP Z,CLAssembleShort
 CP 5
 JP Z,CLSave
 CP 6
 JP Z,CLLoad
 CP 7
 JP Z,CLSaveas
 CP 8
 JP Z,CLNew
 CP 9
 JP Z,CLExit
 LD A,(LastLineOfScreen)
 LD B,A
 LD C,0
 LD HL,StrUsed
 CALL PrintStr
 LD A,(SourceLastBank)
 INC A
 LD H,0
 LD L,A
 ADD HL,HL
 ADD HL,HL
 ADD HL,HL
 CALL PrintDecimalWord
 LD HL,StrKb
 CALL PrintStr
 PUSH BC
 LD A,','
 CALL PrintChar
 POP BC
 INC C
 PUSH BC
 LD A,32
 CALL PrintChar
 POP BC
 INC C
 LD HL,StrFree
 CALL PrintStr
 LD A,(SourceLastBank)
 INC A
 LD L,A
 LD A,SourceNoBanks
 SUB L
 LD H,0
 LD L,A
 ADD HL,HL
 ADD HL,HL
 ADD HL,HL
 CALL PrintDecimalWord
 LD HL,StrKb
 CALL PrintStr
 CALL InputChar
 JP CommandLineEdit
CLFind:
 LD A,C
 ADD A,4
 LD C,A
 CALL CLParseSpaces
 JR C,CLFindCheckString
 CALL CLParseString
CLFindCheckString:
 LD A,(SearchString)
 AND A
 JP Z,CommandLineEdit
 CALL FindString
 JP CommandLineEdit
CLAssembleShort:
 INC C
 JR CLAssembleArgs
CLAssemble:
 LD A,C
 ADD A,8
 LD C,A
CLAssembleArgs:
 LD A,(ModeFlag)
 RES 3,A
 LD (ModeFlag),A
 XOR A
 LD (ObjectFilename),A
 CALL CLParseSpaces
 JR C,CLAssembleDo
 LD DE,StrNonext
 CALL CLParseOptional
 JR Z,CLAssembleNonext
 LD DE,ObjectFilename
 CALL CLParseFilename
 JP C,CLFilenameError
 CALL CLParseSpaces
 JR C,CLAssembleDo
 LD DE,StrNonext
 CALL CLParseOptional
 JP NZ,CLCommandError
CLAssembleNonext:
 LD A,(ModeFlag)
 SET 3,A
 LD (ModeFlag),A
CLAssembleDo:
 LD A,(LastLineOfScreen)
 LD B,A
 LD C,0
 LD HL,StrAssembling
 CALL PrintStr
 CALL Assemble
 PUSH AF
 LD HL,(pParserCurrentLine)
 LD (pSourceScreen),HL
 LD (pSourceCursor),HL
 LD A,(SourceBankActive)
 LD (SourceBankScreen),A
 LD (SourceBankCursor),A
 XOR A
 LD (CursorLastX),A
 LD A,(FirstLineOfScreen)
 LD (CursorSourceY),A
 CALL ClearEditArea
 CALL SourceScreenDump
 POP AF
 JP C,CLAssembleError
 LD A,(ObjectBank)
 LD HL,(pObjectNextCode)
 LD DE,ObjectStartAddr
 SBC HL,DE
 AND A
 JR Z,CLAssembleReport
 LD B,A
 LD DE,0x2000
CLAssembleAddBank:
 ADD HL,DE
 DJNZ CLAssembleAddBank
CLAssembleReport:
 LD A,(LastLineOfScreen)
 LD B,A
 LD C,0
 PUSH HL
 LD HL,StrAssReport
 CALL PrintStr
 POP HL
 CALL PrintDecimalWord
 LD A,(ObjectFilename)
 AND A
 JR Z,CLAssemblePressKey
 LD A,(ModeFlag)
 SET 7,A
 LD (ModeFlag),A
 PUSH BC
 CALL FileBrowse
 PUSH AF
 CALL ClearEditArea
 CALL SourceScreenDump
 POP AF
 POP BC
 JP C,CLFileBrowseError
 LD HL,StrSep
 CALL PrintStr
 LD HL,StrSaving
 CALL PrintStr
 PUSH BC
 CALL SaveTapFile
 POP BC
 LD HL,StrOk
 CALL PrintStr
CLAssemblePressKey:
 CALL InputChar
 JP CommandLineEdit
CLAssembleError:
 PUSH AF
 LD A,(LastLineOfScreen)
 LD B,A
 CALL ClearLine
 POP AF
 CALL PrintError
 JP CommandLineEdit
CLSave:
 LD A,C
 ADD A,4
 LD C,A
 CALL CLParseSpaces
 CALL CLParseSourceFilename
 JR C,CLFilenameError
 LD A,(SourceFilename)
 AND A
 JR Z,CLMissingFilename
 LD A,(ModeFlag)
 SET 7,A
 LD (ModeFlag),A
 LD A,B
 AND A
 JR Z,CLSaveFile
CLSaveSelection:
 CALL FileBrowse
 PUSH AF
 CALL ClearEditArea
 CALL SourceScreenDump
 POP AF
 JR C,CLFileBrowseError
CLSaveFile:
 LD A,(LastLineOfScreen)
 LD B,A
 LD C,0
 LD HL,StrSaving
 CALL PrintStr
 CALL SaveSource
 LD A,15
 CALL C,PrintError
 JP CommandLineEdit
CLFileBrowseError:
 LD A,5
 CALL PrintError
 JP CommandLineEdit
CLFilenameError:
 LD A,3
 CALL PrintError
 JP CommandLineEdit
CLMissingFilename:
 LD A,2
 CALL PrintError
 JP CommandLineEdit
CLSaveas:
 LD A,C
 ADD A,6
 LD C,A
 CALL CLParseSpaces
 CALL CLParseSourceFilename
 JR C,CLFilenameError
 LD A,(SourceFilename)
 AND A
 JR Z,CLMissingFilename
 LD A,(ModeFlag)
 SET 7,A
 LD (ModeFlag),A
 JR CLSaveSelection
CLLoad:
 LD A,C
 ADD A,4
 LD C,A
 CALL CLParseSpaces
 CALL CLParseSourceFilename
 JR C,CLFilenameError
 LD A,B
 AND A
 JR Z,CLLoadSelect
 LD A,(LastLineOfScreen)
 LD B,A
 LD C,0
 LD HL,StrLoading
 CALL PrintStr
 CALL LoadSource
 JR CLFileLoaded
CLLoadSelect:
 LD A,(ModeFlag)
 RES 7,A
 LD (ModeFlag),A
 CALL FileBrowse
 JR C,CLFileBrowseError
 PUSH IX
 POP HL
 LD A,H
 OR L
 JR Z,CLLoadDump
 LD A,(LastLineOfScreen)
 LD B,A
 LD C,0
 LD HL,StrLoading
 CALL PrintStr
 CALL LoadSelected
CLFileLoaded:
 PUSH AF
 LD HL,SourceStartAddr
 LD (pSourceScreen),HL
 LD (pSourceCursor),HL
 LD A,(FirstLineOfScreen)
 LD (CursorSourceY),A
 XOR A
 LD (CursorLastX),A
 LD (SourceBankCursor),A
 LD (SourceBankScreen),A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 POP AF
 CALL C,PrintError
CLLoadDump:
 CALL ClearEditArea
 CALL SourceScreenDump
 JP CommandLineEdit
CLNew:
 LD A,(FirstLineOfScreen)
 LD (CursorSourceY),A
 XOR A
 LD (CursorLastX),A
 LD (SourceFilename),A
 LD (ObjectFilename),A
 LD (SourceBankScreen),A
 LD (SourceBankCursor),A
 LD (SourceBankActive),A
 LD (SourceLastBank),A
 CALL SetSourceMemBank
 CALL ClearSourceBank
 LD HL,SourceStartAddr
 LD (pSourceScreen),HL
 LD (pSourceCursor),HL
 CALL ClearEditArea
 JP CommandLineEdit
CLExit:
 NEXTREG 0x56,0
 NEXTREG 0x57,1
 RST 0
CLCheckPrintable:
 CP 32
 JP C,CLEditSymbol
 EX AF,AF'
 LD A,(NoCharsInLine)
 INC A
 CP 80
 JP Z,CLEditSymbol
 LD (NoCharsInLine),A
 LD C,A
 LD B,0
 LD HL,LineBuffer
 ADD HL,BC
 LD (HL),32
 LD A,(CursorX)
 INC A
 LD (CursorX),A
 CP C
 JR Z,CLAddChar
 LD B,C
 LD C,A
 LD A,B
 SUB C
 LD C,B
 LD B,0
 DEC C
 LD HL,LineBuffer
 ADD HL,BC
 LD C,A
 PUSH HL
 POP DE
 DEC HL
 LDDR
CLAddChar:
 LD HL,LineBuffer
 LD B,0
 LD A,(CursorX)
 LD C,A
 ADD HL,BC
 DEC HL
 EX AF,AF'
 LD (HL),A
 INC HL
 LD A,(LastLineOfScreen)
 LD B,A
 PUSH HL
 PUSH BC
 LD HL,LineBuffer
 LD A,(NoCharsInLine)
 LD C,0
 CALL PrintStrN
 POP BC
 POP HL
 LD A,(HL)
 OR 128
 CALL PrintChar
 JP CLEditSymbol
; Skip spaces in command line, return carry if at line end
CLParseSpaces:
 LD A,C
 LD HL,NoCharsInLine
 CP (HL)
 SCF
 RET Z
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
 LD A,(HL)
 CP 33
 RET NC
 INC C
 JR CLParseSpaces
; Parse command, return command number in A,
; or carry if not valid command
CLParseCommand:
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
 LD A,NoCommands
CLParseCommandNext:
 PUSH HL
 LD H,0
 LD L,A
 DEC L
 SLA L
 LD DE,CommandPointers
 ADD HL,DE
 LD E,(HL)
 INC HL
 LD D,(HL)
 POP HL
 PUSH AF
 PUSH HL
 PUSH BC
 CALL CLCommandCmp
 POP BC
 POP HL
 POP DE
 LD A,D
 RET Z
 DEC A
 JR NZ,CLParseCommandNext
 SCF
 RET
; Parse optional string in (DE), return Z if it is there
CLParseOptional:
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
CLParseOptionalNext:
 LD A,(DE)
 AND A
 JR Z,CLParseOptionalMatch
 CP (HL)
 RET NZ
 INC HL
 INC DE
 INC B
 JR CLParseOptionalNext
CLParseOptionalMatch:
 LD A,C
 ADD A,B
 LD C,A
 XOR A
 RET
; Parse search string, store in search string buffer
CLParseString:
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
 LD DE,SearchString
 LD A,(NoCharsInLine)
 SUB C
 RET Z
 LD B,A
CLPSNext:
 LD A,(HL)
 LD (DE),A
 INC HL
 INC DE
 DJNZ CLPSNext
 XOR A
 LD (DE),A
 RET
; HL points to first letter of command in line buffer,
; DE points to first letter in command string to compare to
; C holds line character number
; return zero flag set on match
CLCommandCmp:
 LD A,(DE)
 LD B,A
 LD A,(HL)
 CP 123
 JR NC,CLCommandCmpCmp
 CP 97
 JR C,CLCommandCmpCmp
 SUB 32
CLCommandCmpCmp:
 CP B
 RET NZ
 INC DE
 INC HL
 INC C
 LD A,(NoCharsInLine)
 CP C
 JR Z,CLCommandCmpEnd
 LD A,(HL)
 CP 32
 JR NZ,CLCommandCmp
CLCommandCmpEnd:
 LD A,(DE)
 AND A
 RET
; If valid file name set file name to given string
; otherwise return carry
; C is symbol number in LineBuffer
; Return number of file name chars in B
; Must be max 10 characters, only letters, numbers and underscore
CLParseSourceFilename:
 LD DE,SourceFilename
CLParseFilename:
 LD HL,LineBuffer
 LD B,0
 ADD HL,BC
 LD (pCommandFilename),HL
CLParseFilenameNext:
 LD A,(NoCharsInLine)
 CP C
 JR Z,CLParseFilenameCopy
 LD A,(HL)
 CP 32
 JR Z,CLParseFilenameCopy
 CP 95
 JR Z,CLParseFilenameCharOk
 CP 48
 RET C
 CP 58
 JR C,CLParseFilenameCharOk
 CP 65
 RET C
 CP 91
 JR C,CLParseFilenameCharOk
 CP 97
 RET C
 CP 123
 CCF
 RET C
CLParseFilenameCharOk:
 INC HL
 INC C
 INC B
 LD A,B
 CP 10
 JR NZ,CLParseFilenameNext
 LD A,(NoCharsInLine)
 CP C
 JR Z,CLParseFilenameCopy
 LD A,(HL)
 CP 32
 JR Z,CLParseFilenameCopy
 SCF
 RET
CLParseFilenameCopy:
 LD HL,(pCommandFilename)
 LD A,B
 AND A
 RET Z
 PUSH BC
CLParseFilenameCopyNext:
 LD A,(HL)
 LD (DE),A
 INC HL
 INC DE
 DJNZ CLParseFilenameCopyNext
 XOR A
 LD (DE),A
 POP BC
 RET

; Clear command line, initialize cursor for source edit
SourceCodeEdit:
 LD A,(LastLineOfScreen)
 LD B,A
 CALL ClearLine
 CALL SetCursorBankAsActive
 LD A,1
 LD (ModeFlag),A
 LD A,(CursorLastX)
 LD (CursorX),A
SCENextInput:
 CALL SourcePrintCursor
 CALL InputChar
 CP 7
 JR NZ,SCENotEdit
 LD A,(CursorX)
 LD (CursorLastX),A
 CALL SourceClearCursor
 JP CommandLineEdit
SCENotEdit:
 CP 4
 JR NZ,SCENotTrueVideo
 CALL ToggleColorTheme
 JR SCENextInput
SCENotTrueVideo:
 CP 8
 JR NZ,SCENotLeft
 LD A,(CursorX)
 AND A
 JR Z,SCENextInput
 CALL SourceClearCursor
 LD A,(CursorX)
 DEC A
 LD (CursorX),A
 LD HL,(pSourceCursor)
 DEC HL
 LD (pSourceCursor),HL
 JR SCENextInput
SCENotLeft:
 CP 9
 JR NZ,SCENotRight
 LD HL,(pSourceCursor)
 LD A,(HL)
 CP 32
 JP C,SCENextInput
 CALL SourceClearCursor
 LD A,(CursorX)
 INC A
 LD (CursorX),A
 LD HL,(pSourceCursor)
 INC HL
 LD (pSourceCursor),HL
 JR SCENextInput
SCENotRight:
 CP 11
 JR NZ,SCENotUp
 LD A,(FirstLineOfScreen)
 LD C,A
 LD A,(CursorSourceY)
 CP C
 JP Z,SCESymbolUp
 CALL SourceClearCursor
SCECursorLineUp:
 CALL SetCursorBankAsActive
 LD HL,(pSourceCursor)
 CALL FindStartOfLine
 DEC HL
 LD A,H
 CP SourceStartHigh
 JR NC,SCEUpFindLineStart
 CALL CursorPrevBank
 JP C,SCENextInput
 CALL SetCursorBankAsActive
 CALL FindEndOfBank
SCEUpFindLineStart:
 CALL FindStartOfLine
 LD (pSourceCursor),HL
 LD A,(CursorSourceY)
 DEC A
 LD (CursorSourceY),A
 XOR A
 LD (CursorX),A
 JP SCENextInput
SCENotUp:
 CP 10
 JR NZ,SCENotDown
 LD A,(LastLineOfScreen)
 SUB 2
 LD C,A
 LD A,(CursorSourceY)
 CP C
 JP Z,SCESymbolDown
 CALL SourceClearCursor
SCECursorLineDown:
 CALL SetCursorBankAsActive
 LD HL,(pSourceCursor)
 CALL FindEndOfLine
 LD A,(HL)
 AND A
 JP Z,SCENextInput
 INC HL
 LD A,(HL)
 AND A
 JR NZ,SCEDownAdjust
 PUSH HL
 CALL CursorNextBank
 POP HL
 JR C,SCEDownAdjust
 CALL SetCursorBankAsActive
 LD HL,SourceStartAddr
SCEDownAdjust:
 LD (pSourceCursor),HL
 LD A,(CursorSourceY)
 INC A
 LD (CursorSourceY),A
 XOR A
 LD (CursorX),A
 JP SCENextInput
SCENotDown:
 CP SymbolUp
 JR NZ,SCENotSUp
SCESymbolUp:
 LD HL,(pSourceScreen)
 DEC HL
 LD A,H
 CP SourceStartHigh
 JR NC,SCESUpAtEOL
 CALL ScreenPrevBank
 JP C,SCENextInput
 CALL SetScreenBankAsActive
 CALL FindEndOfBank
SCESUpAtEOL:
 PUSH HL
 CALL ClearEditArea
 CALL SetScreenBankAsActive
 POP HL
 CALL FindStartOfLine
 LD (pSourceScreen),HL
 CALL SourceScreenDump
 LD A,(CursorSourceY)
 INC A
 LD (CursorSourceY),A
 JP SCECursorLineUp
SCENotSUp:
 CP SymbolDown
 JR NZ,SCENotSDown
SCESymbolDown:
 LD HL,(pSourceCursor)
 CALL FindEndOfLine
 LD A,(HL)
 AND A
 JP Z,SCENextInput
SCESymbolDownDo:
 CALL SetScreenBankAsActive
 LD HL,(pSourceScreen)
 CALL FindEndOfLine
 INC HL
 LD (pSourceScreen),HL
 PUSH HL
 CALL ClearEditArea
 POP HL
 LD A,(HL)
 AND A
 JR NZ,SCESDownDump
 CALL ScreenNextBank
 JR C,SCESDownDump
 LD HL,SourceStartAddr
 LD (pSourceScreen),HL
SCESDownDump:
 CALL SourceScreenDump
 LD A,(CursorSourceY)
 DEC A
 LD (CursorSourceY),A
 CALL SetCursorBankAsActive
 JP SCECursorLineDown
SCENotSDown:
 CP SymbolLeft
 JR NZ,SCENotSLeft
 LD A,(EditAreaLines)
 LD B,0
 LD C,A
SCESLeftN:
 LD HL,(pSourceScreen)
 LD A,L
 AND A
 JR NZ,SCESymbolLeft
 LD A,H
 CP SourceStartHigh
 JP NZ,SCESymbolLeft
 LD A,(SourceBankScreen)
 AND A
 JP Z,SCENextInput
SCESymbolLeft:
 PUSH BC
 CALL ClearEditArea
 CALL SetScreenBankAsActive
 POP BC
 LD HL,(pSourceScreen)
SCESLeftNextLine:
 DEC HL
 LD A,H
 CP SourceStartHigh
 JP NC,SCESLeftAtEOL
 CALL ScreenPrevBank
 JR C,SCESLeftDump
 CALL SetScreenBankAsActive
 CALL FindEndOfBank
SCESLeftAtEOL:
 CALL FindStartOfLine
 LD (pSourceScreen),HL
 DEC BC
 LD A,B
 OR C
 JR NZ,SCESLeftNextLine
SCESLeftDump:
 CALL SourceScreenDump
 XOR A
 LD (CursorX),A
 LD A,(FirstLineOfScreen)
 LD (CursorSourceY),A
 LD A,(SourceBankScreen)
 LD (SourceBankCursor),A
 LD HL,(pSourceScreen)
 LD (pSourceCursor),HL
 JP SCENextInput
SCENotSLeft:
 CP SymbolRight
 JR NZ,SCENotSRight
 LD A,(EditAreaLines)
 LD B,0
 LD C,A
SCESRightN:
 PUSH BC
 CALL ClearEditArea
 POP BC
 CALL SetScreenBankAsActive
 LD HL,(pSourceScreen)
SCESRightNextLine:
 CALL FindEndOfLine
 LD A,(HL)
 AND A
 JR Z,SCESLeftDump
 INC HL
 LD A,(HL)
 AND A
 JR NZ,SCESRightSOL
 CALL ScreenNextBank
 JR C,SCESLeftDump
 CALL SetScreenBankAsActive
 LD HL,SourceStartAddr
SCESRightSOL:
 LD (pSourceScreen),HL
 DEC BC
 LD A,B
 OR C
 JR NZ,SCESRightNextLine
 JR  SCESLeftDump
SCENotSRight:
 CP CapsLeft
 JR NZ,SCENotCLeft
 CALL SourceClearCursor
 LD HL,(pSourceCursor)
 CALL FindStartOfLine
 LD (pSourceCursor),HL
 XOR A
 LD (CursorX),A
 JP SCENextInput
SCENotCLeft:
 CP CapsRight
 JR NZ,SCENotCRight
 CALL SourceClearCursor
 LD HL,(pSourceCursor)
 LD A,(CursorX)
 LD C,A
SCECRightFindEOL:
 LD A,(HL)
 INC C
 INC HL
 CP 32
 JR NC,SCECRightFindEOL
 DEC C
 DEC HL
 LD (pSourceCursor),HL
 LD A,C
 LD (CursorX),A
 JP SCENextInput
SCENotCRight:
 CP CapsUp
 JR NZ,SCENotCUp
 CALL ClearEditArea
 LD A,(FirstLineOfScreen)
 LD (CursorSourceY),A
 XOR A
 LD (CursorX),A
 LD (SourceBankScreen),A
 LD (SourceBankCursor),A
 LD HL,SourceStartAddr
 LD (pSourceScreen),HL
 LD (pSourceCursor),HL
 CALL SourceScreenDump
 JP SCENextInput
SCENotCUp:
 CP CapsDown
 JP NZ,SCENotCDown
 CALL ClearEditArea
 LD A,(SourceLastBank)
 LD (SourceBankScreen),A
 LD (SourceBankCursor),A
 CALL SetScreenBankAsActive
 CALL FindEndOfBank
 INC HL
 LD (pSourceCursor),HL
 XOR A
SCECDownPrevChar:
 LD (CursorX),A
 DEC HL
 LD A,H
 CP SourceStartHigh
 JR C,SCECDownXFound
 LD A,(HL)
 CP 13
 JR Z,SCECDownXFound
 LD A,(CursorX)
 INC A
 JR SCECDownPrevChar
SCECDownXFound:
 INC HL
 LD (pSourceScreen),HL
 LD A,CapsDownLines
SCECDownNextLine:
 EX AF,AF'
 DEC HL
 LD A,H
 CP SourceStartHigh
 JP NC,SCECDownAtEOL
 CALL ScreenPrevBank
 JR C,SCECDownDump
 CALL SetScreenBankAsActive
 CALL FindEndOfBank
SCECDownAtEOL:
 CALL FindStartOfLine
 LD (pSourceScreen),HL
 EX AF,AF'
 DEC A
 JR NZ,SCECDownNextLine
 EX AF,AF'
SCECDownDump:
 CALL SourceScreenDump
 EX AF,AF'
 LD B,A
 LD A,CapsDownLines
 SUB B
 LD B,A
 LD A,(FirstLineOfScreen)
 ADD A,B
 LD (CursorSourceY),A
 JP SCENextInput
SCENotCDown:
 CP ExtendLeft
 JR NZ,SCENotELeft
 LD BC,500
 JP SCESLeftN
SCENotELeft:
 CP ExtendRight
 JR NZ,SCENotERight 
 LD BC,500
 JP SCESRightN
SCENotERight:
 CP 12
 JR NZ,SCENotDelete
 LD A,(CursorX)
 AND A
 JP Z,SCENextInput
 LD HL,(pSourceCursor)
 LD A,(HL)
 AND A
 JR NZ,SCEDelMoveData
 CALL SourceClearCursor
 LD HL,(pSourceCursor)
 DEC HL
 XOR A
 LD (HL),A
 LD (pSourceCursor),HL
 LD A,(CursorX)
 DEC A
 LD (CursorX),A
 JP SCENextInput
SCEDelMoveData:
 CALL FindEndOfBank
 LD DE,(pSourceCursor)
 DEC DE
 XOR A
 SBC HL,DE
 PUSH HL
 POP BC
 LD HL,(pSourceCursor)
 LD (pSourceCursor),DE
 LDIR
 LD (DE),A
 LD A,(CursorX)
 DEC A
 LD (CursorX),A
 CALL ClearEditArea
 CALL SourceScreenDump
 CALL SetCursorBankAsActive
 CALL DefragMemFromActiveBank
 JP SCENextInput
SCENotDelete:
 CP LineDelete
 JR NZ,SCENotLD
 LD HL,(pSourceCursor)
 CALL FindStartOfLine
 LD A,(HL)
 AND A
 JP Z,SCENextInput
 LD (pSourceCursor),HL
 PUSH HL
 CALL FindEndOfLine
 INC HL
 PUSH HL
 EX DE,HL
 LD HL,SourceLastAddr
 INC HL
 AND A
 SBC HL,DE
 PUSH HL
 POP BC
 POP HL
 POP DE
 LDIR
 XOR A
 LD (DE),A
 LD HL,SourceLastAddr
 SBC HL,DE
 JR Z,SCELDAdjust
 PUSH HL
 POP BC
 PUSH DE
 POP HL
 INC DE
 LDIR
SCELDAdjust:
 LD (CursorX),A
 LD HL,(pSourceCursor)
 LD A,(HL)
 AND A
 JR NZ,SCELDDump
 CALL DefragMemFromActiveBank
 LD HL,(pSourceCursor)
 LD A,(HL)
 AND A
 JR NZ,SCELDDump
 CALL CursorNextBank
 JR C,SCELDDump
 LD HL,SourceStartAddr
 LD (pSourceCursor),HL
SCELDDump:
 CALL ClearEditArea
 CALL SourceScreenDump
 CALL SetCursorBankAsActive
 CALL DefragMemFromActiveBank
 JP SCENextInput
SCENotLD:
 CP 13
 JR Z,SCECharInput
 CP 32
 JP C,SCENextInput
SCECharInput:
 PUSH AF
 CALL SourceClearCursor
 LD HL,(pSourceCursor)
 LD A,(HL)
 AND A
 JR NZ,SCECharInsert
 EX DE,HL
 LD HL,SourceLastAddr
 LD BC,SourceReservedMin
 SBC HL,BC
 SBC HL,DE
 CALL C,FreeMemInCursorBank
 POP AF
 JP C,SCEOutOfMem
 CP 13
 JR NZ,SCECharAppend
 LD HL,(pSourceCursor)
 LD (HL),A
 INC HL
 LD (pSourceCursor),HL
 XOR A
 LD (CursorX),A
 LD A,(LastLineOfScreen)
 SUB 2
 LD C,A
 LD A,(CursorSourceY)
 CP C
 JP Z,SCESymbolDownDo
 INC A
 LD (CursorSourceY),A
 JP SCENextInput
SCECharAppend:
 LD E,A
 LD A,(CursorX)
 LD C,A
 INC A
 CP 80
 JP Z,SCENextInput
 LD (CursorX),A
 LD A,(CursorSourceY)
 LD B,A
 LD A,E
 LD HL,(pSourceCursor)
 LD (HL),A
 INC HL
 LD (pSourceCursor),HL
 CALL PrintChar
 JP SCENextInput
SCECharInsert:
 LD HL,SourceLastAddr
 INC HL
 LD BC,SourceReservedMin
 SBC HL,BC
 LD A,(HL)
 AND A
 CALL NZ,FreeMemInCursorBank
 POP AF
 JP C,SCEOutOfMem
 PUSH AF
 CALL FindEndOfBank
 PUSH HL
 POP DE
 INC HL
 LD BC,(pSourceCursor)
 AND A
 SBC HL,BC
 PUSH HL
 POP BC
 PUSH DE
 POP HL
 INC DE
 LDDR
 INC HL
 POP AF
 LD (HL),A
 INC HL
 LD (pSourceCursor),HL
 CP 13
 JR NZ,SCECharIncX
 XOR A
 LD (CursorX),A
 LD A,(LastLineOfScreen)
 LD C,A
 LD A,(CursorSourceY)
 CP C
 JP Z,SCESymbolDownDo
 INC A
 LD (CursorSourceY),A
 CALL ClearEditArea
 CALL SourceScreenDump
 JP SCENextInput
SCECharIncX:
 LD A,(CursorX)
 INC A
 LD (CursorX),A
 LD A,(CursorSourceY)
 LD B,A
 PUSH BC
 CALL ClearLine
 LD HL,(pSourceCursor)
 CALL FindStartOfLine
 POP BC
 CALL PrintLine
 JP SCENextInput
SCEOutOfMem:
 LD A,10
 CALL PrintError
 JP SCENextInput

MemSetup:
 NEXTREG 0x56,SourceStartBank
 NEXTREG 0x57,ObjectStartBank
 RET

; Set current object code bank as active
SetObjectBankAsActive:
 LD A,(ModeFlag)
 BIT 1,A
 RET Z
 RES 1,A
 LD (ModeFlag),A
 LD A,(ObjectBank)
 ADD A,ObjectStartBank
 NEXTREG 0x57,A
 RET

; Set current vars bank as active
SetVarsBankAsActive:
 LD A,(ModeFlag)
 BIT 1,A
 RET NZ
 SET 1,A
 LD (ModeFlag),A
 LD A,(VarsBank)
 ADD A,VarsStartBank
 NEXTREG 0x57,A
 RET

; Set object bank to 0 and set as active
; Set next code address to start
ObjectGoToStart:
 LD A,(ModeFlag)
 RES 1,A
 LD (ModeFlag),A
 LD A,ObjectStartBank
 NEXTREG 0x57,A
 XOR A
 LD (ObjectBank),A
 LD HL,ObjectStartAddr
 LD (pObjectNextCode),HL
 RET

; Set vars bank to 0 and set as active
VarsGoToStartBank:
 LD A,(ModeFlag)
 SET 1,A
 LD (ModeFlag),A
 LD A,VarsStartBank
 NEXTREG 0x57,A
 XOR A
 LD (VarsBank),A
 RET

; Increment object bank and set as active,
; return carry if no more banks
ObjectNextBankActive:
 LD A,(ObjectBank)
 INC A
 CP ObjectNoBanks
 CCF
 RET C
 LD (ObjectBank),A
 ADD A,ObjectStartBank
 NEXTREG 0x57,A
 LD A,(ModeFlag)
 RES 1,A
 LD (ModeFlag),A
 RET

; Increment vars bank and set as active,
; return carry if no more banks
VarsNextBankActive:
 LD A,(VarsBank)
 INC A
 CP VarsNoBanks
 CCF
 RET C
 LD (VarsBank),A
 ADD A,VarsStartBank
 NEXTREG 0x57,A
 LD A,(ModeFlag)
 SET 1,A
 LD (ModeFlag),A
 RET

; Set active object code bank, relative value in A
SetVarsMemBank:
 ADD A,VarsStartBank
 NEXTREG 0x57,A
 RET
 
; Set active object code bank, relative value in A
SetObjectMemBank:
 ADD A,ObjectStartBank
 NEXTREG 0x57,A
 RET
 
; Set active source code bank, relative value in A
SetSourceMemBank:
 ADD A,SourceStartBank
 NEXTREG 0x56,A
 RET

; Set active bank to one less, return carry if at start bank
; Load active bank if not
SourcePrevBankActive:
 LD A,(SourceBankActive)
 SUB 1
 RET C
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 AND A
 RET

; Increase active bank by one, return carry if at last (used) bank
; Load active bank if not
SourceNextBankActive:
 LD A,(SourceBankActive)
 LD HL,SourceLastBank
 CP (HL)
 CCF
 RET C
 INC A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 AND A
 RET

; Increase the number of used bank by one, return carry if out of memory
; Set last (used) bank as active bank if not
SourceNewBankActive:
 LD A,(SourceLastBank)
 INC A
 CP SourceNoBanks
 CCF
 RET C
 LD (SourceLastBank),A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 CALL ClearSourceBank
 AND A
 RET

; Set screen bank to one less, return carry if at start bank
ScreenPrevBank:
 LD A,(SourceBankScreen)
 SUB 1
 RET C
 LD (SourceBankScreen),A
 RET

; Increase screen bank by one, return carry if at last (used) bank
ScreenNextBank:
 LD A,(SourceBankScreen)
 LD HL,SourceLastBank
 CP (HL)
 CCF
 RET C
 INC A
 LD (SourceBankScreen),A
 RET

; Set cursor bank to one less, return carry if at start bank
CursorPrevBank:
 LD A,(SourceBankCursor)
 SUB 1
 RET C
 LD (SourceBankCursor),A
 RET

; Increase cursor bank by one, return carry if at last (used) bank
CursorNextBank:
 LD A,(SourceBankCursor)
 LD HL,SourceLastBank
 CP (HL)
 CCF
 RET C
 INC A
 LD (SourceBankCursor),A
 RET

; Set active bank to cursor bank
SetCursorBankAsActive:
 LD A,(SourceBankActive)
 LD C,A
 LD A,(SourceBankCursor)
 CP C
 RET Z
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 RET

; Set active bank to screen bank
SetScreenBankAsActive:
 PUSH BC
 LD A,(SourceBankActive)
 LD C,A
 LD A,(SourceBankScreen)
 CP C
 POP BC
 RET Z
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 RET

ClearSourceBank:
 LD HL,SourceStartAddr
 PUSH HL
 POP DE
 INC DE
 LD BC,0x1FFF
 XOR A
 LD (HL),A
 LDIR
 RET

; return pointer in HL to last non-0 char in bank
FindEndOfBank:
 LD HL,SourceLastAddr
FEOBCheck0:
 LD A,(HL)
 AND A
 RET NZ
 DEC HL
 LD A,L
 AND A
 JR NZ,FEOBCheck0
 LD A,H
 CP SourceStartHigh
 JR NZ,FEOBCheck0
 RET

; HL must hold pointer to char in line (or end-of-line 0/13)
; Return pointer to first symbol of line in HL
FindStartOfLine:
 LD A,L
 AND A
 JR NZ,FSOLCheckReturn
 LD A,H
 CP SourceStartHigh
 RET Z
FSOLCheckReturn:
 DEC HL
 LD A,(HL)
 CP 13
 JR NZ,FindStartOfLine
 INC HL
 RET

; HL must hold pointer to char in line (or end-of-line 0/13)
; Return pointer to line ending (0/13)
FindEndOfLine:
 LD A,(HL)
 INC HL
 CP 32
 JR NC,FindEndOfLine
 DEC HL
 RET

; Move data upwards in memory to free memory in cursor bank,
; and set the screen + cursor pointers and banks as needed,
; return carry if out of memory
FreeMemInCursorBank:
 CALL SetCursorBankAsActive
FMFindBankWithSpace:
 CALL SourceNextBankActive
 CALL C,SourceNewBankActive
 RET C
 LD HL,SourceReserved0
 ADD HL,HL
 EX DE,HL
 LD HL,SourceStartAddr
 LD A,(HL)
 AND A
 JR Z,FMFirst0Found
 LD H,SourceEndHigh
 SBC HL,DE
 LD A,(HL)
 AND A
 JR NZ,FMFindBankWithSpace
FMFindLastDatabyte:
 DEC HL
 OR (HL)
 JR Z,FMFindLastDatabyte
 INC HL
FMFirst0Found:
 PUSH HL ; Push address of first 0
 LD DE,SourceStartAddr
 AND A
 SBC HL,DE
 PUSH HL ; Push size of data in bank
 CALL SourcePrevBankActive
 CALL FindEndOfBank
 INC HL
 EX DE,HL
 LD HL,SourceReserved0
 LD A,(SourceBankCursor)
 LD C,A
 LD A,(SourceBankActive)
 CP C
 JR Z,FMCalcDataToCopy
 ADD HL,HL
FMCalcDataToCopy:
 LD A,H
 ADD A,0x20
 LD H,A
 LD BC,SourceStartAddr
 ADD HL,BC
 SBC HL,DE
 PUSH HL
 POP BC
 PUSH DE
 POP HL
 INC BC
 LD A,13
FMGoBackByLines:
 DEC HL
 DEC BC
 CP (HL)
 JR NZ,FMGoBackByLines
 BIT 7,B
 JR Z,FMGoBackByLines
 INC HL
 EX DE,HL
 XOR A
 SBC HL,DE
 LD (MemCopySize),HL
 LD BC,(MemCopySize)
 LD HL,ObjectStartAddr
 EX DE,HL
 LD (pMemCopyStart),HL
 PUSH HL
 PUSH HL
 PUSH BC
 LDIR
 POP BC
 POP DE
 POP HL
 INC DE
 DEC BC
 LD (HL),A
 LDIR
 CALL SourceNextBankActive
 POP BC
 POP DE
 LD A,B
 OR C
 JR Z,FMCopyToHigherBank
 LD HL,(MemCopySize)
 ADD HL,DE
 EX DE,HL
 LDDR
FMCopyToHigherBank:
 LD HL,ObjectStartAddr
 LD DE,SourceStartAddr
 LD BC,(MemCopySize)
 LDIR
 CALL SourcePrevBankActive
 LD A,(SourceBankCursor)
 LD C,A
 LD A,(SourceBankActive)
 CP C
 JR Z,FMAdjustPointers
 CALL FindEndOfBank
 INC HL
 JP FMFirst0Found
FMAdjustPointers:
 LD DE,(pSourceCursor)
 LD HL,(pMemCopyStart)
 DEC HL
 SBC HL,DE
 RET NC
 PUSH DE
 CALL SourceNextBankActive
 POP DE
 LD HL,(pMemCopyStart)
 EX DE,HL
 AND A
 SBC HL,DE
 ADD HL,SourceStartAddr
 LD (pSourceCursor),HL
 LD A,(SourceBankCursor)
 INC A
 LD (SourceBankCursor),A
 LD HL,(pSourceScreen)
 EX DE,HL
 DEC HL
 SBC HL,DE
 RET NC
 LD HL,(pMemCopyStart)
 EX DE,HL
 AND A
 SBC HL,DE
 ADD HL,SourceStartAddr
 LD (pSourceScreen),HL
 LD A,(SourceBankScreen)
 INC A
 LD (SourceBankScreen),A
 RET

; Move data one bank down (active bank is overwritten)
; Last bank is reduced by one if it is not 0
ContractMemBanks:
 LD A,(SourceLastBank)
 AND A
 RET Z
 LD A,(SourceBankActive)
 PUSH AF
ContractNextBank:
 LD A,(SourceBankActive)
 LD C,A
 LD A,(SourceLastBank)
 CP C
 JR NZ,CMBCopy
 DEC A
 LD (SourceLastBank),A
 POP AF
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 RET
CMBCopy:
 CALL SourceNextBankActive
 LD HL,SourceStartAddr
 LD DE,ObjectStartAddr
 LD BC,0x2000
 LDIR
 CALL SourcePrevBankActive
 LD DE,SourceStartAddr
 LD HL,ObjectStartAddr
 LD BC,0x2000
 LDIR
 CALL SourceNextBankActive
 JR ContractNextBank


DefragMemFromActiveBank:
 LD A,(SourceBankActive)
 PUSH AF
DefragNext:
 LD A,(SourceLastBank)
 LD C,A
 LD A,(SourceBankActive)
 CP C
 JR NZ,DefragCheckEmpty
DefragExit:
 POP AF
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 RET
DefragCheckEmpty:
 LD A,(SourceStartAddr)
 AND A
 JR NZ,DefragCalcSpace
 CALL ContractMemBanks
 JR DefragNext
DefragCalcSpace:
 CALL FindEndOfBank
 INC HL
 LD (pMemCopyStart),HL
 EX DE,HL
 LD HL,SourceLastAddr
 INC HL
 AND A
 SBC HL,DE
 LD DE,SourceReservedMax
 SCF
 SBC HL,DE
 JR C,DefragExit
 INC HL
 PUSH HL
 CALL SourceNextBankActive
 POP BC
 LD HL,SourceStartAddr
 LD A,(HL)
 AND A
 JR Z,DefragNext
DefragSkipByLine:
 LD A,(HL)
 INC HL
 DEC BC
 CP 32
 JR NC,DefragSkipByLine
 AND A
 JR NZ,DefragNextReturn
 LD DE,SourceStartAddr
 SBC HL,DE
 LD (MemCopySize),HL
 LD BC,(MemCopySize)
 EX DE,HL
 LD DE,ObjectStartAddr
 LDIR
 DEC DE
 LD BC,(MemCopySize)
 LDDR
 JR DefragPaste
DefragNextReturn:
 BIT 7,B
 JR Z,DefragSkipByLine
 LD DE,SourceStartAddr
 AND A
 SBC HL,DE
 LD (MemCopySize),HL
 LD BC,(MemCopySize)
 EX DE,HL
 LD DE,ObjectStartAddr
 LDIR
 EX DE,HL
 LD HL,SourceLastAddr
 INC HL
 AND A
 SBC HL,DE
 PUSH HL
 POP BC
 EX DE,HL
 LD DE,SourceStartAddr
 LDIR
 LD HL,SourceLastAddr
 XOR A
 LD (HL),A
 PUSH HL
 POP DE
 DEC DE
 LD BC,(MemCopySize)
 DEC BC
 LDDR
DefragPaste:
 CALL SourcePrevBankActive
 LD HL,ObjectStartAddr
 LD DE,(pMemCopyStart)
 LD BC,(MemCopySize)
 LDIR
 CALL SourceNextBankActive
 JP DefragNext


; Remove illegal characters from source code
LegalizeSourceCodeInBank:
 CALL FindEndOfBank
 LD A,(HL)
 AND A
 RET Z
 PUSH HL
 POP DE
 INC DE
LSCIBNext:
 LD A,(HL)
 CP 13
 JR Z,LSCIBCharDone
 CP 32
 JR C,LSCIBRemove
 CP 128
 JR C,LSCIBCharDone
 CP 156
 JR NZ,LSCIBRemove
 LD A,96
 LD (HL),A
 JR LSCIBCharDone
LSCIBRemove:
 PUSH HL
 PUSH HL
 EX DE,HL
 AND A
 SBC HL,DE
 PUSH HL
 POP BC
 POP DE
 POP HL
 PUSH HL
 INC HL
 LDIR
 POP HL
 DEC DE
LSCIBCharDone:
 DEC HL
 LD A,H
 CP SourceStartHigh
 JR NC,LSCIBNext
 RET


; Truncate all lines in active bank to max 79 characters (excl enter)
TruncateLinesInBank:
 CALL FindEndOfBank
 LD A,(HL)
 AND A
 RET Z
 INC HL
 EX DE,HL
 LD HL,SourceStartAddr
TLIBNextLine:
 PUSH HL
 AND A
 SBC HL,DE
 POP HL
 JR Z,TLIBClearEnd
 LD BC,0
TLIBNextChar:
 LD A,(HL)
 CP 13
 INC HL
 JR Z,TLIBLineEndEnter
 INC BC
 PUSH HL
 AND A
 SBC HL,DE
 POP HL
 JR NZ,TLIBNextChar
 SBC HL,BC
 LD BC,79
 ADD HL,BC
 EX DE,HL
 JR TLIBClearEnd
TLIBLineEndEnter:
 PUSH HL
 PUSH BC
 POP HL
 AND A
 LD BC,80
 SBC HL,BC
 PUSH HL
 POP BC
 POP HL
 JR C,TLIBNextLine
 INC BC
 DEC HL
 EX DE,HL
 SBC HL,DE
 PUSH HL
 PUSH DE
 POP HL
 SBC HL,BC
 EX DE,HL
 POP BC
 PUSH DE
 LDIR
 POP HL
 INC HL
 JR TLIBNextLine
TLIBClearEnd:
 XOR A
 LD (DE),A
 LD HL,SourceLastAddr
 SBC HL,DE
 PUSH HL
 POP BC
 PUSH DE
 POP HL
 INC DE
 LDIR
 RET 

SetPalette:
 NEXTREG 0x43,0x30
 LD HL,ColorThemes
 LD A,(ColorThemeNumber) 
 ADD A,A
 LD B,0
 LD C,A
 ADD HL,BC
 LD A,(HL)
 NEXTREG 0x40,InkColor
 NEXTREG 0x41,A
 INC HL
 LD A,(HL)
 NEXTREG 0x40,PaperColor
 NEXTREG 0x44,A
 NEXTREG 0x44,0
 RET
 
ToggleColorTheme:
 LD A,(ColorThemeNumber)
 INC A
 CP NoColorThemes
 LD (ColorThemeNumber),A
 JR C,SetPalette
 XOR A
 LD (ColorThemeNumber),A
 JR SetPalette 

SetupTilemap:
 NEXTREG 0x6C,0
 NEXTREG 0x6E,0x00
 NEXTREG 0x6F,0x20
 NEXTREG 0x6B,0xE1
 NEXTREG 0x43,0xB0
 NEXTREG 0x4C,0x0F
 NEXTREG 0x68,0x90
 ; Make tilemap definitions for symbol 32-127 + 160-255
 LD HL,TileDefSpace
MakeNextCharSet:
 LD IX,CharGraphics
 LD B,96
MakeNextChar:
 LD C,64
MakeNextPixel:
 LD A,C
 AND 7
 JR NZ,GetPixelBit
 LD E,(IX+0)
 INC IX
GetPixelBit:
 LD A,(CurrentPaper)
 SLA E
 JR NC,PlotTilePixel
 LD A,(CurrentInk)
PlotTilePixel:
 BIT 0,C
 JR NZ,OddTilePixel
 SWAPNIB
 LD (HL),A
 JR TilePixelDone
OddTilePixel:
 OR (HL)
 LD (HL),A
 INC HL
TilePixelDone:
 DEC C
 JR NZ,MakeNextPixel
 DJNZ MakeNextChar
 ; use inverse symbols 32-127 for symbol 160-255
 LD A,(CurrentPaper)
 LD C,A
 LD A,(CurrentInk)
 LD (CurrentPaper),A
 LD A,C
 LD (CurrentInk),A
 LD A,H
 CP TileDefEndHigh
 RET Z
 ADD A,4
 LD H,A
 JR MakeNextCharSet 

CurrentPaper:
 DEFB PaperColor
CurrentInk:
 DEFB InkColor

ClearScreen:
 LD HL,TilemapBase
 LD B,32
ClearNextRow:
 LD C,80
ClearNextTile:
 LD (HL),32
 INC HL
 DEC C
 JR NZ,ClearNextTile
 DJNZ ClearNextRow
 RET
 
SkipLines:
 PUSH BC
 LD BC,80
 ADD HL,BC
 POP BC
 DJNZ SkipLines
 RET

ClearEditArea:
 LD HL,TilemapBase
 LD A,(FirstLineOfScreen)
 LD B,A
 AND A
 CALL NZ,SkipLines
 LD A,(EditAreaLines)
 LD B,A
 JR ClearNextRow

SetupScreen:
 LD BC,0x243B
 LD A,5
 OUT (C),A
 INC B
 IN A,(C)
 BIT 2,A
 JR Z,DrawSeparatorLine
 LD A,CroppedScreenFirstLine
 LD (FirstLineOfScreen),A
 LD (CursorSourceY),A
 LD C,A
 LD A,CroppedScreenLastLine
 LD (LastLineOfScreen),A
 DEC A
 SUB C
 LD (EditAreaLines),A
 LD HL,TilemapBase
 LD B,C
 LD A,'*'
DrawTopCropLines:
 CALL FillNextLine
 DJNZ DrawTopCropLines
 LD A,(EditAreaLines)
 ADD A,2
 LD B,A
 CALL SkipLines
 LD A,(LastLineOfScreen)
 LD C,A
 LD A,31
 SUB C
 LD B,A
 LD A,'*'
DrawBottomCropLines:
 CALL FillNextLine
 DJNZ DrawBottomCropLines
; Draw separator line between edit area and command line
DrawSeparatorLine:
 LD HL,TilemapBase
 LD A,(FirstLineOfScreen)
 LD C,A 
 LD A,(EditAreaLines)
 ADD A,C
 LD B,A
 CALL SkipLines
 LD A,'-'
; Fill next line with the symbol in A
FillNextLine:
 LD C,80
FillNextTile:
 LD (HL),A
 INC HL
 DEC C
 JR NZ,FillNextTile
 RET

; Line number in B
ClearLine:
 LD HL,TilemapBase
 LD DE,80
 LD A,B
 AND A
 LD A,32
 JR Z,CLDrawSpace
CLSkipLine:
 ADD HL,DE
 DJNZ CLSkipLine
CLDrawSpace:
 LD (HL),A
 INC HL
 DEC E
 JR NZ,CLDrawSpace
 RET

 ; Char in A, x in C, y in B
PrintChar:
 LD E,A
 AND 127
 CP 32
 RET C
 LD A,C
 CP 80
 RET NC
 LD A,B
 CP 32
 RET NC
 LD H,0
 LD L,C
 LD A,B
 AND A
 LD A,E
 JR Z,PrintTile
 LD DE,80
PrintSkipRow:
 ADD HL,DE
 DJNZ PrintSkipRow
PrintTile:
 ADD HL,TilemapBase
 LD (HL),A
 RET

; Print string at HL, x in C, y in B, length in A
; On return BC holds coords to next char on screen
PrintStrN:
 LD E,A
 LD A,C
 CP 80
 RET NC
 LD A,(HL)
 PUSH HL
 PUSH DE
 PUSH BC
 CALL PrintChar
 POP BC
 POP DE
 POP HL
 LD A,E
 DEC A
 RET Z
 INC C
 INC HL
 JR PrintStrN

; Print 0 determined string at HL, x in C, y in B
; On return BC holds coords to next char on screen
PrintStr:
 LD A,C
 CP 80
 RET NC
 LD A,(HL)
 AND A
 RET Z
 PUSH HL
 PUSH BC
 CALL PrintChar
 POP BC
 POP HL
 INC C
 INC HL
 JR PrintStr

; Print 0 determined string at HL inverted, x in C, y in B
; On return BC holds coords to next char on screen
PrintStrInv:
 LD A,C
 CP 80
 RET NC
 LD A,(HL)
 AND A
 RET Z
 PUSH HL
 PUSH BC
 SET 7,A
 CALL PrintChar
 POP BC
 POP HL
 INC C
 INC HL
 JR PrintStrInv

; Print 'enter' or 0 determined string at HL, y in B, x = 0
PrintLine:
 LD C,0
PLNext:
 LD A,(HL)
 AND A
 RET Z
 CP 13
 RET Z
 PUSH HL
 PUSH BC
 CALL PrintChar
 POP BC
 POP HL
 INC C
 INC HL
 JR PLNext

; Print value in A as a Hex number, BC holds coords
; On exit BC holds coords to next char on screen
PrintHexByte:
 LD D,2
 LD E,A
 SWAPNIB
PHBNextDigit:
 AND 15
 ADD A,48
 CP 58
 JR C,PHBPrintDigit
 ADD A,7
PHBPrintDigit:
 PUSH BC
 PUSH DE
 CALL PrintChar
 POP DE
 POP BC
 INC C
 LD A,E
 DEC D
 JR NZ,PHBNextDigit
 RET

; Print value in HL as a decimal number, BC holds coords
; On exit BC holds coords to next char on screen
PrintDecimalWord:
 LD IX,DecimalDigitsWord
 LD A,0x85
PDWNextDigit:
 PUSH AF
 LD E,(IX+0)
 INC IX
 LD D,(IX+0)
 INC IX
 XOR A
PDWSubtract:
 INC A
 SBC HL,DE
 JR NC,PDWSubtract
 ADD HL,DE
 DEC A
 POP DE
 JR NZ,PDWNon0
 BIT 7,D
 JR NZ,PDWDigitPrinted
 JR PDWPrintDigit
PDWNon0:
 RES 7,D
PDWPrintDigit:
 ADD A,48
 PUSH IX
 PUSH HL
 PUSH DE
 PUSH BC
 CALL PrintChar
 POP BC
 POP DE
 POP HL
 POP IX
 LD A,C
 CP 80
 JR NC,PDWDigitPrinted
 INC C
PDWDigitPrinted:
 DEC D
 LD A,D
 AND 0x7F
 LD A,D
 JR NZ,PDWNextDigit
 AND A
 RET Z
 LD A,C
 CP 80
 RET NC
 LD A,48
 PUSH BC
 CALL PrintChar
 POP BC
 INC C
 RET

; Print error and wait for keypress, error number in A
PrintError:
 LD C,0
 LD H,C
 DEC A
 ADD A,A
 LD L,A
 LD DE,ErrorStringPointers
 ADD HL,DE
 EX DE,HL
 LD A,(DE)
 LD L,A
 INC DE
 LD A,(DE)
 LD H,A
 LD A,(LastLineOfScreen)
 LD B,A
 CALL PrintStr
 PUSH BC
 CALL InputChar
 POP BC
 CALL ClearLine
 RET

SourceClearCursor:
 CALL SetCursorBankAsActive
 LD A,(CursorX)
 LD C,A
 LD A,(CursorSourceY)
 LD B,A
 LD HL,(pSourceCursor)
 LD A,(HL)
 CP 32
 JR NC,SCCPrintable
 LD A,32
SCCPrintable:
 CALL PrintChar
 RET

SourcePrintCursor:
 CALL SetCursorBankAsActive
 LD A,(CursorX)
 LD C,A
 LD A,(CursorSourceY)
 LD B,A
 LD HL,(pSourceCursor)
 LD A,(HL)
 CP 32
 JR NC,SPCPrintable
 LD A,32
SPCPrintable:
 OR 128
 CALL PrintChar
 RET

; Dump source code from screen start address onto screen
SourceScreenDump:
 CALL SetScreenBankAsActive
 LD A,(FirstLineOfScreen)
 LD B,A
 LD HL,(pSourceScreen)
SSDNextLine:
 LD C,0
SSDNextChar:
 LD A,(HL)
 INC HL
 AND A
 RET Z
 CP 13
 JR Z,SSDEOL
 PUSH HL
 PUSH BC
 CALL PrintChar
 POP BC
 POP HL
 INC C
 JR SSDNextChar
SSDEOL:
 INC B
 LD A,(LastLineOfScreen)
 DEC A
 CP B
 RET Z
 LD A,(HL)
 AND A
 JR NZ,SSDNextLine
 CALL SourceNextBankActive
 RET C
 LD HL,SourceStartAddr
 JR SSDNextLine

; Get main key + shift key pressed
GetKeypress:
 XOR A
 LD (KeypressSymbol),A
 LD (KeypressShift),A
 LD E,8
 LD HL,KeyInputDefOld
NextKeyRowOld:
 LD C,0xFE
 LD B,(HL)
 INC HL
 IN A,(C)
 LD D,A
 LD B,5
NextKeyCheckOld:
 SRL D
 JR C,KeyCheckOldDone
 LD A,(HL)
 CP CapsShift
 JR Z,ShiftPressed
 CP SymbolShift
 JR Z,ShiftPressed
 LD C,A
 LD A,(KeypressSymbol)
 AND A
 JR NZ,MultiKeypress
 LD A,C
 LD (KeypressSymbol),A
 JR KeyCheckOldDone
ShiftPressed:
 LD (KeypressShift),A
KeyCheckOldDone:
 INC HL
 DJNZ NextKeyCheckOld
 DEC E
 JR NZ,NextKeyRowOld
 LD HL,KeyInputDefExt
NextKeyRowExt:
 LD BC,0x243B
 LD A,0xB0
 ADD A,E
 OUT (C),A
 LD B,0x25
 IN A,(C)
 LD D,A
 LD B,8
NextKeyCheckExt:
 SRL D
 JR NC,KeyCheckExtDone
 LD A,(HL)
 CP Extend
 JR Z,ExtendPressed
 LD C,A
 LD A,(KeypressSymbol)
 AND A
 JR NZ,MultiKeypress
 LD A,C
 LD (KeypressSymbol),A
 JR KeyCheckExtDone
ExtendPressed:
 LD (KeypressShift),A
KeyCheckExtDone:
 INC HL
 DJNZ NextKeyCheckExt
 INC E
 LD A,E
 CP 2
 JR NZ,NextKeyRowExt
 RET
MultiKeypress:
 XOR A
 LD (KeypressSymbol),A
 LD (KeypressShift),A
 RET

GetKeypressChange:
 CALL GetKeypress
 LD A,(LastKeySymbol)
 LD C,A
 LD A,(KeypressShift)
 LD (LastKeyShift),A
 LD A,(KeypressSymbol)
 LD (LastKeySymbol),A
 SUB C
 RET NZ
 LD (KeypressSymbol),A
 RET

; wait for input, return input in A
InputChar:
 CALL GetKeypressChange
 LD A,(KeypressSymbol)
 AND A
 JR Z,InputChar
 CP 6
 JR NZ,NotCapsLock
 LD A,(KeypressMode)
 XOR 1
 LD (KeypressMode),A
 JR InputChar
NotCapsLock:
 CP 12
 JR NZ,NotDelete
 LD A,(KeypressShift)
 CP SymbolShift
 LD A,LineDelete
 RET Z
 LD A,12
 RET
NotDelete:
 LD C,A
 LD A,(KeypressShift)
 CP SymbolShift
 JR NZ,CheckCapsArrows
 LD A,C
 CP 8
 JR C,InputCheckNumbers
 CP 12
 JR NC,InputCheckNumbers
 ADD A,16
 RET
CheckCapsArrows:
 CP CapsShift
 JR NZ,CheckExtendArrows
 LD A,C
 CP 32
 JR Z,CapsSpace
 CP 8
 JR C,InputCheckNumbers
 CP 12
 JR NC,InputCheckNumbers
 ADD A,8
 RET
CapsSpace:
 LD A,3
 RET
CheckExtendArrows:
 CP Extend
 JR NZ,InputCheckNumbers
 LD A,C
 CP 8
 JR C,InputCheckNumbers
 CP 10
 JR NC,InputCheckNumbers
 ADD A,12
 RET
InputCheckNumbers:
 LD A,C
 CP 48
 RET C
 CP 58
 LD A,(KeypressShift)
 JR NC,InputCheckLetters
 LD HL,SymbolShiftNumbers
 CP SymbolShift
 JR Z,ShiftAndNumber
 LD HL,CapsShiftNumbers
 CP CapsShift
 LD A,C
 RET NZ
ShiftAndNumber:
 LD B,0
 LD A,C
 SUB 48
 LD C,A
 ADD HL,BC
 LD A,(HL)
 CP 6
 RET NZ
 LD A,(KeypressMode)
 XOR 1
 LD (KeypressMode),A
 JP InputChar
InputCheckLetters:
 CP CapsShift
 JR Z,CheckCapsShift
 CP SymbolShift
 JR NZ,CheckOtherShift
 LD A,C
 CP 97
 RET C
 CP 123
 RET NC
 LD HL,SymbolShiftLetters
 LD B,0
 SUB 97
 LD C,A
 ADD HL,BC
 LD A,(HL)
 AND A
 RET NZ
 JP InputChar
CheckOtherShift:
 XOR A
CheckCapsShift:
 LD D,A
 LD A,C
 CP 97
 RET C
 CP 123
 RET NC
 LD A,D
 AND A
 JR Z,CheckKeypressMode
 LD D,1
CheckKeypressMode:
 LD A,(KeypressMode)
 AND 1
 XOR D
 LD A,C
 RET Z
 SUB 32
 RET

; Copy string from (HL) to (DE), 0 determined
StrCopy:
 LD A,(HL)
 LD (DE),A
 INC HL
 INC DE
 AND A
 JR NZ,StrCopy
 RET

; Copy string from (HL) to (DE),
; Determined by 0 or after B chars
; On return HL and DE points to char after copy
StrNCopy:
 LD A,(HL)
 LD (DE),A
 INC HL
 INC DE
 AND A
 RET Z
 DJNZ StrNCopy
 RET

; Compare strings in (HL) and (DE)
; Return Z if strings match
StrCmp:
 LD A,(DE)
 CP (HL)
 RET NZ
 INC HL
 INC DE
 AND A
 JR NZ,StrCmp
 RET

; Compare strings in (HL) and (DE), max B chars
; Return Z if strings match within B chars
StrNCmp:
 LD A,(DE)
 CP (HL)
 RET NZ
 INC HL
 INC DE
 AND A
 RET Z
 DJNZ StrNCmp
 XOR A
 RET

; Compare ':' determined label in source (HL) to 0 determined string (DE)
; Return Z if strings match
; Assume: Length of both strings > 2, optimized for speedy search
LabelCmp:
 LD A,(DE)
 CP (HL)
 RET NZ
 INC HL
 INC DE
 LD A,(DE)
 CP (HL)
 RET NZ
 INC HL
 INC DE
 LD A,(DE)
 CP (HL)
 RET NZ
 INC HL
 INC DE
LabelCmpNext:
 LD A,(HL)
 CP ':'
 JR Z,LabelCmpColon
 LD A,(DE)
 AND A
 JR Z,LabelCmp0
 CP (HL)
 RET NZ
 INC HL
 INC DE
 JR LabelCmpNext
LabelCmpColon:
 LD A,(DE)
 AND A
 RET
LabelCmp0:
 OR 1
 RET


; Return carry if file name is invalid
; Must be max 10 characters, only letters, numbers and underscore
CheckValidFileName:
 LD HL,SourceFilename
CheckValidFilenameCustom:
 LD B,10
CVFNCheckNext:
 LD A,(HL)
 CP 48
 RET C
 CP 58
 JR C,CVFNSymbolOk
 CP 65
 RET C
 CP 91
 JR C,CVFNSymbolOk
 CP 97
 RET C
 CP 123
 JR C,CVFNSymbolOk
 CP 126
 JR Z,CVFNSymbolOk
 SCF
 RET
CVFNSymbolOk:
 INC HL
 LD A,(HL)
 AND A
 RET Z
 DJNZ CVFNCheckNext
 SCF
 RET


AppendAsm:
 LD HL,SourceFilename
 LD DE,StrAsm
AppendEndingToName:
 INC HL
 LD A,(HL)
 AND A
 JR NZ,AppendEndingToName
 EX DE,HL
 CALL StrCopy
 RET

RemoveAsmEnding:
 LD HL,SourceFilename
RemoveEndingFromName:
 INC HL
 LD A,(HL)
 CP '.'
 JR NZ,RemoveEndingFromName
 XOR A
 LD (HL),A
 RET


; Save source code to file on disc
; Return carry set for write error
SaveSource:
 CALL CheckValidFileName
 LD A,3
 RET C
 CALL AppendAsm
 LD A,'$'
 LD IX,SourceFilename
 LD B,0x0E
 RST 8
 DEFB 0x9A
 PUSH AF
 CALL RemoveAsmEnding
 XOR A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 POP AF
 JP C,SSWriteErrorExit
SSSaveNextBank:
 PUSH AF
 LD IX,SourceStartAddr
 CALL FindEndOfBank
 LD BC,SourceStartAddr
 LD A,(HL)
 AND A
 JR Z,SSBankSaved
 INC HL
 SBC HL,BC
 PUSH HL
 POP BC
 POP AF
 PUSH AF
 RST 8
 DEFB 0x9E
SSBankSaved:
 POP DE
 LD A,D
 JR C,SSWriteError
 PUSH AF
 CALL SourceNextBankActive
 POP DE
 LD A,D
 JR NC,SSSaveNextBank
 RST 8
 DEFB 0x9B
 CALL SetCursorBankAsActive
 AND A
 RET
SSWriteError:
 RST 8
 DEFB 0x9B
SSWriteErrorExit:
 CALL SetCursorBankAsActive
 SCF
 RET


; Load source code file from disc
; Arrange in banks and remove illegal format
; Return carry set for error, error number in A
LoadSource:
 CALL CheckValidFileName
 LD A,3
 RET C
 CALL AppendAsm
 LD IX,SourceFilename
 LD A,'$'
 LD B,1
 RST 8
 DEFB 0x9A
 PUSH AF
 CALL RemoveAsmEnding
 POP AF
LSFileOpened:
 PUSH AF
 XOR A
 LD (SourceBankScreen),A
 LD (SourceBankCursor),A
 LD (SourceBankActive),A
 LD (SourceLastBank),A
 LD (CursorLastX),A
 LD (CursorSourceY),A
 CALL SetSourceMemBank
 CALL ClearSourceBank
 POP AF
 JP C,LSReadErrorExit
 LD IX,SourceStartAddr
 LD HL,0x2000
 LD BC,SourceReserved0
 SBC HL,BC
 PUSH HL
 POP BC
LSLoadNextBank:
 PUSH BC
 PUSH AF
 RST 8
 DEFB 0x9D
 POP DE
 LD A,D
 POP DE
 JP C,LSReadError
 EX DE,HL
 SBC HL,BC
 JP NZ,LSExitSuccess
 PUSH AF
 CALL LegalizeSourceCodeInBank
 CALL TruncateLinesInBank
 CALL FindEndOfBank
 LD BC,0
 LD (MemCopySize),BC
 LD A,(HL)
 CP 13
 JR Z,LSNewBank
 AND A
 JR Z,LSNewBankSetup
 PUSH HL
 CALL FindStartOfLine
 POP DE
 INC DE
 EX DE,HL
 AND A
 SBC HL,DE
 LD (MemCopySize),HL
 PUSH HL
 POP BC
 EX DE,HL
 LD DE,ObjectStartAddr
 PUSH BC
 LDIR
 PUSH HL
 POP DE
 DEC DE
 POP BC
 LDDR
LSNewBank:
 CALL SourceNewBankActive
LSNewBankSetup:
 POP DE
 LD A,D
 JP C,LSMemError
 LD BC,(MemCopySize)
 LD A,B
 OR C
 LD A,D
 LD HL,ObjectStartAddr
 LD DE,SourceStartAddr
 JR Z,LSPrepareNextLoad
 LDIR
LSPrepareNextLoad:
 PUSH DE
 POP IX
 LD HL,SourceLastAddr
 INC HL
 LD BC,SourceReserved0
 AND A
 SBC HL,DE
 SBC HL,BC
 PUSH HL
 POP BC
 JP LSLoadNextBank
LSExitSuccess:
 RST 8
 DEFB 0x9B
 CALL LegalizeSourceCodeInBank
 CALL TruncateLinesInBank
 LD A,(SourceStartAddr)
 AND A
 JR NZ,LSExitOk
 LD A,(SourceLastBank)
 DEC A
 LD (SourceLastBank),A
LSExitOk:
 AND A
 RET
LSReadError:
 RST 8
 DEFB 0x9B
 XOR A
 LD (SourceLastBank),A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 CALL ClearSourceBank
LSReadErrorExit:
 LD A,14
 SCF
 RET
LSMemError:
 RST 8
 DEFB 0x9B
 XOR A
 LD (SourceLastBank),A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 CALL ClearSourceBank
 LD A,10
 SCF
 RET
 
; Load source file, IX points to file name
; Arrange in banks and remove illegal format
; Return carry set for error, error number in A
LoadSelected:
 LD A,'$'
 LD B,1
 RST 8
 DEFB 0x9A
 JP LSFileOpened

; Assemble source code and save to executable .tap file
; if a file name is specified.
; Return carry if there is an error and error number in A.
Assemble:
 XOR A
 LD (EntryFlag),A
 LD A,(ModeFlag)
 RES 2,A
 SET 4,A
 LD (ModeFlag),A
AssInitiateRun:
 CALL ObjectGoToStart
 LD HL,SourceStartAddr
 LD (pParserCurrentLine),HL
 LD (pParserNextSymbol),HL
 XOR A
 LD (NoORG),A
 LD (SourceBankActive),A
 CALL SetSourceMemBank
 LD A,0xFF
 LD (ObjectORGHeaderBank),A
AssDEFINE:
 LD HL,(pParserNextSymbol)
 CALL AssParseEmptyLines
 JR C,AssMissingORGError
 CALL AssParseLabel
 JR C,AssFirstORG
 LD DE,StrDefine
 CALL LabelCmp
 JR NZ,AssMissingORGError
AssDEFINECheckEOL:
 CALL AssGoToNL
 JR NC,AssDEFINENextVar
 AND A
 JR NZ,AssSyntaxError
AssMissingORGError:
 LD A,ErrorORGExpected
 SCF
 RET
AssSyntaxError:
 LD A,ErrorSyntax
 SCF
 RET
AssDEFINENextVar:
 CALL AssParseEmptyLines
 JR C,AssMissingORGError
 CALL AssParseSpaces
 CALL AssParseVarAssign
 JR C,AssFirstORG
 PUSH BC
 PUSH HL
 CALL AssParseExpression
 POP DE
 JR NC,AssDEFINEAssignOk
 POP BC
 AND A
 SCF
 RET NZ
 LD A,ErrorInvalidAssignment
 RET
AssDEFINEAssignOk:
 LD HL,ModeFlag
 BIT 2,(HL)
 JR NZ,AssDEFINEStoreVar
 POP BC
 JR AssDEFINECheckEOL
AssDEFINEStoreVar:
 EX DE,HL
 LD DE,(ExprResult)
 LD A,(ExprResultHigh)
 POP BC
 CALL AssStoreVariable
 JR C,AssOutOfMemory
 JR Z,AssMultiVarDef
 JR AssDEFINECheckEOL
AssBadNumber:
 LD A,ErrorInvalidNumber
 SCF
 RET
AssMultiVarDef:
 LD A,ErrorMultidefOfVariable
 SCF
 RET
AssFirstORG:
 CALL AssParseSpaces
 LD HL,(pParserNextSymbol)
 LD DE,StrOrg
 CALL AssParseString
 JP NZ,AssMissingORGError
 LD A,(HL)
 CP 32
 JP NZ,AssMissingORGError
 LD (pParserNextSymbol),HL
 CALL AssParseSpaces
AssNewORGArg:
 CALL AssParseORGArgument
 JR C,AssBadNumber
 BIT 5,A
 JR NZ,AssBadNumber
 PUSH BC
 POP HL
 CALL AssStartNewORGSegment
 JR C,AssOutOfMemory
 LD A,(NoORG)
 AND A
 JR NZ,AssParseEOL
 LD A,ErrorTooManyCodeBlocks
 SCF
 RET
AssParseEOL:
 CALL AssGoToNL
 JR NC,AssParseNewCodeLine
 AND A
 JP Z,AssEOF
 JP AssSyntaxError
AssOutOfMemory:
 LD A,ErrorOutOfMemory
 SCF
 RET
AssParseNewCodeLine:
 CALL AssParseEmptyLines
 JP C,AssEOF
 CALL AssParseLabel
 JR C,AssNotLabel
 LD A,(ModeFlag)
 BIT 2,A
 JR NZ,AssParseEOL
 CALL AssStoreLabelVariable
 JR C,AssOutOfMemory
 JP Z,AssMultiVarDef
 JR AssParseEOL
AssNotLabel:
 CALL AssParseSpaces
 LD HL,(pParserNextSymbol)
 LD DE,StrOrg
 CALL AssParseString
 JR NZ,AssNotORG
 LD A,(HL)
 CP 32
 JP NZ,AssParseInstruction
 LD (pParserNextSymbol),HL
 CALL AssParseSpaces
 JP AssNewORGArg
AssNotORG:
 LD HL,(pParserNextSymbol)
 LD DE,StrDefb
 CALL AssParseString
 JP NZ,AssNotDEFB
 LD A,(HL)
 CP 32
 JP NZ,AssParseInstruction
 LD (pParserNextSymbol),HL
 CALL AssParseSpaces
AssNextDEFBArg:
 CALL AssParseExpression
 JR NC,AssDEFBTestMode
 AND A
 JR Z,AssDEFBTestString
 SCF
 RET
AssDEFBTestMode:
 LD E,A
 LD A,(ModeFlag)
 BIT 2,A
 LD A,E
 JR Z,AssDEFBStoreByte
 BIT 6,A
 JP NZ,AssByteExpected
 LD A,(ExprResult)
AssDEFBStoreByte:
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 JR AssDEFBArgOk
AssDEFBTestString:
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CP 0x22
 JP NZ,AssInvalidArgument
 INC HL
 LD A,(HL)
 CP 0x22
 JP Z,AssInvalidArgument
AssDEFBStringNextChar:
 LD A,(HL)
 INC HL
 CP 32
 JP C,AssInvalidArgument
 CP 128
 JP NC,AssInvalidArgument
 CP 0x22
 JR Z,AssDEFBStringEnd
 PUSH HL
 CALL StoreCodeByte
 POP HL
 JP C,AssOutOfMemory
 JR AssDEFBStringNextChar
AssDEFBStringEnd:
 LD (pParserNextSymbol),HL
AssDEFBArgOk:
 CALL AssParseSpaces
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CP ','
 JP NZ,AssParseEOL
 INC HL
 LD (pParserNextSymbol),HL
 JP AssNextDEFBArg
AssNotDEFB:
 LD HL,(pParserNextSymbol)
 LD DE,StrDefw
 CALL AssParseString
 JP NZ,AssNotDEFW
 LD A,(HL)
 CP 32
 JP NZ,AssParseInstruction
 LD (pParserNextSymbol),HL
 CALL AssParseSpaces
AssNextDEFWArg:
 CALL AssParseExpression
 JR NC,AssDEFWTestMode
 AND A
 SCF
 RET NZ
 JP AssInvalidArgument
AssDEFWTestMode:
 LD E,A
 LD A,(ModeFlag)
 BIT 2,A
 LD A,E
 JR Z,AssDEFWStoreWord
 BIT 4,A
 JP NZ,AssWordExpected
 LD BC,(ExprResult)
AssDEFWStoreWord:
 LD A,C
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 LD A,B
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 CALL AssParseSpaces
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CP ','
 JP NZ,AssParseEOL
 INC HL
 LD (pParserNextSymbol),HL
 JP AssNextDEFWArg 
AssNotDEFW:
 LD HL,(pParserNextSymbol)
 LD DE,StrDefs
 CALL AssParseString
 JP NZ,AssParseInstruction
 LD A,(HL)
 CP 32
 JP NZ,AssParseInstruction
 LD (pParserNextSymbol),HL
 CALL AssParseSpaces
 CALL AssParseNumber
 JP C,AssBadNumber
 BIT 5,A
 JP NZ,AssBadNumber
 BIT 4,A
 JP NZ,AssBadNumber
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CP 32
 JR NZ,AssDEFSSkip
 CALL AssParseSpaces
 LD HL,(pParserNextSymbol)
 LD DE,StrSet
 CALL AssParseString
 JR NZ,AssDEFSSkip
 LD A,(HL)
 CP 32
 JP NZ,AssSyntaxError
 LD (pParserNextSymbol),HL
 CALL AssParseSpaces
 LD DE,(ExprResult)
 PUSH DE
 CALL AssParseExpression
 POP DE
 JP C,AssByteExpected
 BIT 6,A
 JP NZ,AssByteExpected
AssDEFSWriteNext:
 LD A,E
 OR D
 JP Z,AssParseEOL
 DEC DE
 LD A,(ExprResult)
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 JR AssDEFSWriteNext
AssDEFSSkip:
 LD HL,(ObjectPC)
 ADD HL,BC
 LD (ObjectPC),HL
AssDEFSSkipNextBlock:
 LD DE,ObjectLastAddr
 INC DE
 LD HL,(pObjectNextCode)
 EX DE,HL
 AND A
 SBC HL,DE
 EX DE,HL
 PUSH BC
 POP HL
 AND A
 SBC HL,DE
 JR C,AssDEFSSkipLastBlock
 JR Z,AssDEFSSkipLastBlock
 PUSH HL
 POP BC
 CALL ObjectNextBankActive
 JP C,AssOutOfMemory
 LD HL,ObjectStartAddr
 LD (pObjectNextCode),HL
 JR AssDEFSSkipNextBlock
AssDEFSSkipLastBlock:
 LD HL,(pObjectNextCode)
 ADD HL,BC
 LD (pObjectNextCode),HL
 JP AssParseEOL
AssParseInstruction:
 LD B,8
 XOR A
 LD HL,SourceArgSpecs
 LD DE,SourceOpcode
AssPINextClear:
 LD (HL),A
 LD (DE),A
 INC HL
 INC DE
 DJNZ AssPINextClear
 LD HL,(pParserNextSymbol)
 LD DE,SourceOpcode
 LD C,0
 LD B,7
AssPICopyNextLetter:
 LD A,(HL)
 CP 97
 JR C,AssPINotLowerCase
 CP 123
 JR NC,AssPINotLowerCase
 SUB 32
AssPINotLowerCase:
 LD (DE),A
 INC HL
 INC DE
 INC C
 LD A,(HL)
 CP 33
 JR C,AssPIEndOfWord
 CP ';'
 JR Z,AssPIEndOfWord
 DJNZ AssPICopyNextLetter
 JP AssSyntaxError
AssPIEndOfWord:
 LD (pParserNextSymbol),HL
 CP 32
 LD A,0
 LD (DE),A
 LD HL,NoValueArgs
 LD (HL),A
 LD DE,SourceArgSpecs
 JR NZ,AssPIEndOfArgs
 LD B,7
AssPINextArgElement:
 PUSH BC
 PUSH DE
 CALL AssParseSpaces
 CALL AssParseArgElement
 POP DE
 JR NC,AssPINotExpressionError
 POP BC
 RET
AssPINotExpressionError:
 LD (DE),A
 BIT 7,A
 JR Z,AssPIArgElementStored
 LD A,(NoValueArgs)
 INC A
 CP 3
 JR NZ,AssPIArgStoreValue
 POP BC
 JP AssInvalidArgument
AssPIArgStoreValue:
 PUSH BC
 POP HL
 LD (NoValueArgs),A
 CP 1
 JR NZ,AssPIArgStoreValue2
 LD (ValueArg1),HL
 JR AssPIArgElementStored
AssPIArgStoreValue2:
 LD (ValueArg2),HL
AssPIArgElementStored:
 POP BC
 AND A
 JR Z,AssPIEndOfArgs
 INC DE
 DJNZ AssPINextArgElement
AssPIEndOfArgs:
 XOR A
 LD (DE),A
 LD HL,SourceOpcode
 LD A,C
 CP 5
 JR NC,AssMatchZ80N7
 LD DE,OpZ80
 LD C,NoZ80Opcodes
AssZ80MatchNext:
 LD B,4
 PUSH DE
 CALL AssCompareStringN
 POP DE
 JR Z,AssOpcode4Found
 PUSH HL
 EX DE,HL
 LD DE,7
 ADD HL,DE
 EX DE,HL
 POP HL
 DEC C
 JR NZ,AssZ80MatchNext
 LD A,(ModeFlag)
 BIT 3,A
 JP NZ,AssSyntaxError
 LD C,NoZ80N4Opcodes
AssZ80N4MatchNext:
 LD B,4
 PUSH DE
 CALL AssCompareStringN
 POP DE
 JR Z,AssOpcode4Found
 PUSH HL
 EX DE,HL
 LD DE,7
 ADD HL,DE
 EX DE,HL
 POP HL
 DEC C
 JR NZ,AssZ80N4MatchNext
 JP AssSyntaxError
AssOpcode4Found:
 INC DE
 INC DE
 INC DE
 INC DE
 EX DE,HL
 JR AssZ80ArgsMatch
AssMatchZ80N7:
 LD DE,OpZ80N7
 LD C,NoZ80N7Opcodes
AssZ80N7MatchNext:
 LD B,7
 PUSH DE
 CALL AssCompareStringN
 POP DE
 JR Z,AssOpcode7Found
 PUSH HL
 EX DE,HL
 LD DE,10
 ADD HL,DE
 EX DE,HL
 POP HL
 DEC C
 JR NZ,AssZ80N7MatchNext
 JP AssSyntaxError
AssOpcode7Found:
 LD HL,7
 ADD HL,DE
AssZ80ArgsMatch:
 LD E,(HL)
 INC HL
 LD D,(HL)
 INC HL
 LD C,(HL)
AssZ80ArgsMatchNextSet:
 LD A,(ModeFlag)
 RES 5,A
 LD (ModeFlag),A
 EX DE,HL
 LD (pArgSpecsExpected),HL
 EX DE,HL
 LD HL,SourceArgSpecs
 LD B,7
 XOR A
 LD (NextValueArg),A
AssZ80ArgsMatchNextSpec:
 PUSH BC
 LD A,(DE) ; expected spec
 BIT 7,A
 JP NZ,AssZ80ArgsMatchValueArg
 BIT 6,A
 JR NZ,AssZ80ArgsMatchRegConst
 BIT 5,A
 JR NZ,AssZ80ArgsMatchMode
 CP (HL)
 JP Z,AssZ80ArgsSpecIsMatching
 CP 4
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,(HL) ; source code spec
 CP 22
 JR Z,AssZ80ArgsMinus
 CP 3
 JR Z,AssZ80ArgsDisplacementOmitted
 AND %10000011
 CP %10000010
 JP NZ,AssZ80ArgsSpecMismatch
 DEC HL
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsDisplacementOmitted:
 POP BC
 INC DE
 INC DE
 DEC B
 DEC B
 LD A,(ModeFlag)
 SET 5,A
 LD (ModeFlag),A
 JP AssZ80ArgsMatchNextSpec
AssZ80ArgsMinus:
 INC HL
 LD A,(HL)
 DEC HL
 AND %10000011
 CP %10000000
 JP NZ,AssZ80ArgsSpecMismatch
 PUSH DE
 CALL AssGetArgValue
 LD A,E
 POP DE
 CP 129
 JP NC,AssZ80ArgsSpecMismatch
 PUSH AF
 LD A,4
 LD (HL),A
 POP AF
 NEG
 JP Z,AssZ80ArgsSpecIsMatching
 PUSH DE
 LD E,A
 CALL AssSetArgValue
 POP DE
 INC HL
 SET 5,(HL)
 DEC HL
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchMode:
 CALL AssGetNextArgValue
 LD A,(HL)
 CP 0x80
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,C
 ADD A,32
 EX DE,HL
 CP (HL)
 EX DE,HL
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchRegConst:
 CALL AssGetNextArgValue
 LD A,(HL)
 AND 0x81
 CP 0x81
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,C
 ADD A,64
 EX DE,HL
 CP (HL)
 EX DE,HL
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching 
AssZ80ArgsMatchValueArg:
 CALL AssGetNextArgValue
 LD A,(DE)
 CP 253
 JR NC,AssZ80ArgsMatchByte
 CP 245
 JR Z,AssZ80ArgsMatchWord
 CP 249
 JR NC,AssZ80ArgsMatchWord
 CP 248
 JR Z,AssZ80ArgsMatchReg
 CP 247
 JR Z,AssZ80ArgsMatchBit
 LD A,(HL)
 CP 0x80
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,C
 AND 0xC7
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching 
AssZ80ArgsMatchBit:
 LD A,(HL)
 AND 0x81
 CP 0x80
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,C
 AND 0xF8
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching 
AssZ80ArgsMatchReg:
 LD A,(HL)
 CP 0x81
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchByte:
 LD A,(HL)
 AND 0x81
 CP 0x80
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,(ModeFlag)
 BIT 2,A
 JP Z,AssZ80ArgsSpecIsMatching
 BIT 6,(HL)
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,(DE)
 CP 254
 JR C,AssZ80ArgsMatchSignedByte
 JP NZ,AssZ80ArgsSpecIsMatching
 BIT 5,(HL)
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchSignedByte:
 BIT 5,(HL)
 JP NZ,AssZ80ArgsSpecIsMatching
 BIT 7,C
 JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchWord:
 LD A,(HL)
 AND 0x81
 CP 0x80
 JP NZ,AssZ80ArgsSpecMismatch
 LD A,(DE)
 CP 245
 JP Z,AssZ80ArgsSpecIsMatching
 CP 251
 JP Z,AssZ80ArgsSpecIsMatching
 CP 250
 JR Z,AssZ80ArgsMatchRelative
 JR C,AssZ80ArgsMatchSignedWord
; BIT 5,(HL)
; JP NZ,AssZ80ArgsSpecMismatch
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchSignedWord:
 BIT 5,(HL)
 JP NZ,AssZ80ArgsSpecIsMatching
 BIT 7,B
 JP NZ,AssZ80ArgsSpecMismatch 
 JP AssZ80ArgsSpecIsMatching
AssZ80ArgsMatchRelative:
; LD A,(ModeFlag)
; BIT 2,A
; JP Z,AssZ80ArgsSpecIsMatching
; BIT 5,(HL)
; JP NZ,AssZ80ArgsSpecMismatch  
AssZ80ArgsSpecIsMatching:
 POP BC
 LD A,(HL)
 AND A
 JR Z,AssZ80ArgsSpecSetMatching
 INC HL
 INC DE
 DEC B
 JP NZ,AssZ80ArgsMatchNextSpec
 JR AssZ80ArgsSpecSetMatching
AssZ80ArgsSpecMismatch:
 POP BC
 LD HL,(pArgSpecsExpected)
 LD DE,12
 ADD HL,DE
 EX DE,HL
 DEC C
 JP NZ,AssZ80ArgsMatchNextSet
 JP AssInvalidArgument
AssZ80ArgsSpecSetMatching:
 LD HL,(pArgSpecsExpected)
 LD B,7
 XOR A
 LD (NextValueArg),A
 LD (ValueSpec1),A
 LD (ValueSpec2),A
AssAdjustNextArgSpec:
 LD A,(HL)
 BIT 7,A
 JR NZ,AssANASValueArg
 AND 0x60
 JP Z,AssANASOk
 CALL AssRemoveValue
 JP AssANASOk
AssANASValueArg:
 CP 253
 JR Z,AssANASDisplacement
 JR NC,AssANASByte
 CP 250
 JR Z,AssANASRelative
 CP 248
 JR Z,AssANASStore
 JR NC,AssANASWord
 CP 246
 JR Z,AssANASRST
 JR NC,AssANASRegister
 CALL AssGetArgValue
 LD A,D
 LD D,E
 LD E,A
 CALL AssSetArgValue
 JR AssANASWord
AssANASDisplacement:
 LD E,A
 LD A,(ModeFlag)
 BIT 5,A
 LD A,E
 JR Z,AssANASStore
 LD DE,0
 CALL AssInsertValue
 JR AssANASStore
AssANASByte:
 LD A,255
 JR AssANASStore
AssANASRelative:
 LD A,(ModeFlag)
 BIT 2,A
 JR Z,AssANASByte
 PUSH HL
 LD HL,(ObjectPC)
 INC HL
 INC HL
 CALL AssGetArgValue
 EX DE,HL
 AND A
 SBC HL,DE
 LD A,H
 AND A
 JR Z,AssANASRelativeForward
 INC A
 JR Z,AssANASRelativeBackward
AssANASRelativeOutOfRange:
 POP HL
 LD A,ErrorRelativeOutOfRange
 SCF
 RET
AssANASRelativeForward:
 BIT 7,L
 JR NZ,AssANASRelativeOutOfRange
 LD E,L
 POP HL
 CALL AssSetArgValue
 JR AssANASByte
AssANASRelativeBackward:
 BIT 7,L
 JR Z,AssANASRelativeOutOfRange
 LD E,L
 POP HL
 CALL AssSetArgValue
 JR AssANASByte
AssANASRST:
 CALL AssGetArgValue
 SRL E
 SRL E
 SRL E
 CALL AssSetArgValue
AssANASRegister:
 LD A,248
 JR AssANASStore
AssANASWord:
 LD A,251
AssANASStore:
 CALL AssStoreNextValueSpec
AssANASOk:
 LD A,(HL)
 AND A
 JR Z,AssEncode
 INC HL
 DEC B
 JP NZ,AssAdjustNextArgSpec
AssEncode:
 ; C holds layout byte, B last instruction code byte
 ; IX points to Layout byte in specs
 LD HL,(pArgSpecsExpected)
 LD DE,7
 ADD HL,DE
 LD C,(HL)
 PUSH HL
 POP IX
 LD B,(IX+4)
 LD A,B
 AND A
 JR NZ,AssEncode4bytes
 BIT 7,C
 JR NZ,AssEncode2bytes
 LD B,(IX+1)
 CALL AssPrepareLastCodeByte
 LD A,B
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 JR AssEncodeByte
AssEncode2bytes:
 LD B,(IX+2)
 CALL AssPrepareLastCodeByte
 LD A,(IX+1)
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 LD A,B
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 LD A,(ValueSpec1)
 CP 253
 LD A,(ValueArg1)
 JR Z,AssEncode2bytesCodeDisp
 LD A,(ValueSpec2)
 CP 253
 LD A,(ValueArg2)
 JR NZ,AssEncodeByte
AssEncode2bytesCodeDisp:
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 JR AssEncodeByte 
AssEncode4bytes:
 CALL AssPrepareLastCodeByte 
 LD A,(IX+1)
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 LD A,(IX+2)
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 LD A,(ValueSpec1)
 CP 253
 LD A,(ValueArg1)
 JR Z,AssEncode4bytesCodeDisp
 LD A,(ValueArg2)
AssEncode4bytesCodeDisp:
 CALL StoreCodeByte
 JP C,AssOutOfMemory
AssEncode4bytesLast:
 LD A,B
 CALL StoreCodeByte
 JP C,AssOutOfMemory
AssEncodeByte:
 LD A,(ValueSpec1)
 CP 255
 LD A,(ValueArg1)
 JR NZ,AssEncodeByte2
 CALL StoreCodeByte
 JP C,AssOutOfMemory
AssEncodeByte2:
 LD A,(ValueSpec2)
 CP 255
 LD A,(ValueArg2)
 JR NZ,AssEncodeWord
 CALL StoreCodeByte
 JP C,AssOutOfMemory
AssEncodeWord:
 LD A,(ValueSpec1)
 LD HL,(ValueArg1)
 CP 251
 JR Z,AssEncodeWordStore
 LD A,(ValueSpec2)
 LD HL,(ValueArg2)
 CP 251
 JP NZ,AssParseEOL
AssEncodeWordStore:
 EX DE,HL
 LD A,E
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 LD A,D
 CALL StoreCodeByte
 JP C,AssOutOfMemory
 JP AssParseEOL
AssEOF:
 LD A,(ObjectORGHeaderBank)
 INC A
 CALL NZ,AssStoreORGSize
 LD A,(ModeFlag)
 AND A
 BIT 2,A
 JR NZ,AssEOFFindEntry
 SET 2,A
 LD (ModeFlag),A
 JP AssInitiateRun
AssEOFFindEntry:
 LD HL,StrEntry
 LD B,5
 CALL AssFindVariable
 SCF
 CCF
 RET NZ
 AND A
 LD A,ErrorInvalidENTRY
 SCF
 RET NZ
 LD (EntryAddress),DE
 LD A,1
 LD (EntryFlag),A
 AND A
 RET
AssByteExpected:
 LD A,ErrorByteExpected
 SCF
 RET
AssWordExpected:
 LD A,ErrorWordExpected
 SCF
 RET
AssVarNotFound:
 LD A,ErrorVariableNotFound
 SCF
 RET
AssInvalidArgument:
 LD A,ErrorInvalidArgument
 SCF
 RET

; C holds layout byte, B last instruction code byte
; Return reg8/bit/rst modified code byte in B
AssPrepareLastCodeByte:
 PUSH AF
 LD A,(ValueSpec1)
 CP 248
 JR NZ,AssPLCBspot1spec2
 LD A,(ValueArg1)
 BIT 5,C
 JR Z,AssPLCBspot1spec1Merge
 ADD A,A
 ADD A,A
 ADD A,A
AssPLCBspot1spec1Merge:
 OR B
 LD B,A
 LD A,(ValueSpec2)
 CP 248
 JR NZ,AssPLCBFinish
 LD A,(ValueArg2)
 BIT 5,C
 JR NZ,AssPLCBspot2spec2Merge
 ADD A,A
 ADD A,A
 ADD A,A
AssPLCBspot2spec2Merge:
 OR B
 LD B,A
 JR AssPLCBFinish
AssPLCBspot1spec2:
 LD A,(ValueSpec2)
 CP 248
 JR NZ,AssPLCBFinish
 LD A,(ValueArg2)
 BIT 5,C
 JR Z,AssPLCBspot1spec2Merge
 ADD A,A
 ADD A,A
 ADD A,A
AssPLCBspot1spec2Merge:
 OR B
 LD B,A
AssPLCBFinish:
 POP AF
 RET

; If at first value, move second value to first place
; No registers affected
AssRemoveValue:
 PUSH AF
 PUSH HL
 LD A,(NextValueArg)
 AND A
 JR NZ,AssRemoveValueRet
 LD HL,(ValueArg2)
 LD (ValueArg1),HL
AssRemoveValueRet:
 POP HL
 POP AF
 RET

; Value spec in A is stored in next value arg spec spot
; No registers affected
AssStoreNextValueSpec:
 PUSH AF
 LD A,(NextValueArg)
 INC A
 LD (NextValueArg),A
 CP 2
 JR Z,AssSNVS2
 POP AF
 LD (ValueSpec1),A
 RET
AssSNVS2:
 POP AF
 LD (ValueSpec2),A
 RET

; Return current argument value in DE
; without adjusting pointer
; Only DE affected
AssGetArgValue:
 PUSH AF
 LD A,(NextValueArg)
 CP 1
 JR Z,AssGAV2
 LD DE,(ValueArg1)
 POP AF
 RET
AssGAV2:
 LD DE,(ValueArg2)
 POP AF
 RET
 
; Set current argument value to value in DE
; without adjusting pointer
; No registers affected
AssSetArgValue:
 PUSH AF
 LD A,(NextValueArg)
 CP 1
 JR Z,AssSAV2
 LD (ValueArg1),DE
 POP AF
 RET
AssSAV2:
 LD (ValueArg2),DE
 POP AF
 RET

; Return next argument value in BC
; and increment value pointer
; Only AF and BC registers affected
AssGetNextArgValue:
 LD A,(NextValueArg)
 INC A
 LD (NextValueArg),A
 CP 2
 JR Z,AssGNAV2
 LD BC,(ValueArg1)
 RET
AssGNAV2:
 LD BC,(ValueArg2)
 RET

; Insert argument value at NextValueArg spot
; and if at spot 1 move value 1 to spot 2
; Value in DE, no registers affected
AssInsertValue:
 PUSH AF
 LD A,(NextValueArg)
 AND A
 JR Z,AssIV1
 LD (ValueArg2),DE
 POP AF
 RET
AssIV1:
 PUSH HL
 LD HL,(ValueArg1)
 LD (ValueArg1),DE
 LD (ValueArg2),HL
 POP HL
 POP AF
 RET
 

; Store byte in A in next code position
; and update pointer and program counter
; Shift to next bank if necessary
; Return carry if out of memory
; A, BC, DE, IX, IY untouched
StoreCodeByte:
 EX AF,AF'
 CALL SetObjectBankAsActive
 LD HL,(pObjectNextCode)
 LD A,H
 CP ObjectEndHigh
 JR Z,SCBNewBank
SCBBankOk:
 EX AF,AF'
 LD (HL),A
 INC HL
 LD (pObjectNextCode),HL
 LD HL,(ObjectPC)
 INC HL
 LD (ObjectPC),HL
 AND A
 RET
SCBNewBank:
 CALL ObjectNextBankActive
 RET C
 LD HL,ObjectStartAddr
 JR SCBBankOk

; HL points to label in source code
; B holds label size
; Store label variable or carry if out of memory
AssStoreLabelVariable:
 EX DE,HL
 LD HL,(ObjectPC)
 EX DE,HL
 XOR A
 JP AssStoreVariable

; Store ORG size in ORG header
AssStoreORGSize:
 LD A,(ObjectORGHeaderBank)
 CALL SetObjectMemBank
 LD HL,(pObjectORGHeader)
 LD C,(HL)
 INC HL
 LD B,(HL)
 INC HL
 EX DE,HL
 LD HL,(ObjectPC)
 AND A
 SBC HL,BC
 EX DE,HL
 LD (HL),E
 INC HL
 LD (HL),D
 LD A,(ModeFlag)
 RES 1,A
 LD (ModeFlag),A
 LD A,(ObjectBank)
 CALL SetObjectMemBank
 RET

; First, store the previous ORG segment size
; Store ORG segment start (in HL) in code and leave room for size
; Return carry if out of memory
AssStartNewORGSegment:
 PUSH HL
 LD A,(ObjectORGHeaderBank)
 INC A
 CALL NZ,AssStoreORGSize
 CALL SetObjectBankAsActive
 POP HL
 LD (ObjectPC),HL
 EX DE,HL
 LD HL,(pObjectNextCode)
 INC HL
 INC HL
 INC HL
 LD A,L
 AND 0xFC
 LD L,A
 LD A,H
 CP ObjectEndHigh
 JR Z,ASNOSNewBank
ASNOSStore:
 LD (pObjectORGHeader),HL
 LD A,(ObjectBank)
 LD (ObjectORGHeaderBank),A
 LD (HL),E
 INC HL
 LD (HL),D
 INC HL
 INC HL
 INC HL
 LD (pObjectNextCode),HL
 LD A,(NoORG)
 INC A
 LD (NoORG),A
 AND A
 RET
ASNOSNewBank:
 CALL ObjectNextBankActive
 RET C
 LD HL,ObjectStartAddr
 JR ASNOSStore

; Takes a variable pointer in HL
; Returns bank number in A and address in HL
VarPointerToBankAndAddress:
 LD A,H
 AND 0xE0
 SRL A
 SWAPNIB
 PUSH AF
 LD A,H
 AND 0x1F
 LD H,A
 PUSH BC
 LD BC,VarsStartAddr
 ADD HL,BC
 POP BC
 POP AF
 RET
 
; Takes Address in HL and bank number in A
; Returns variable pointer in HL
BankAndAddressToVarPointer:
 PUSH AF
 LD A,H
 AND 0x1F
 LD H,A
 POP AF
 SWAPNIB
 SLA A
 OR H
 LD H,A
 RET
 
; Search for variable match
; On entry HL points to variable name in source code,
; B holds the variable name length
; Return zero if found,
; then high byte of value in A and lower bytes in DE
; Otherwise DE points to the placeholder for where
; the pointer to the new variable should be stored
; In any case HL and BC are preserved
AssFindVariable:
 LD A,(ModeFlag)
 BIT 4,A
 RET NZ
 LD (pSourceVar),HL
 CALL VarsGoToStartBank
 LD HL,VarsStartAddr
 PUSH BC
 PUSH HL
AFVNext:
 LD A,(HL)
 CP B
 JR NZ,AFVCheckBranch
 EX DE,HL
 LD HL,(pSourceVar)
 DEC HL
AFVNextSymbol:
 INC HL
 INC DE
 LD A,(DE)
 CP (HL)
 JR NZ,AFVCheckBranch
 DJNZ AFVNextSymbol
 POP HL
 POP BC
 LD D,0
 LD E,B
 INC HL
 ADD HL,DE
 LD E,(HL)
 INC HL
 LD D,(HL)
 INC HL
 LD A,(HL)
 LD HL,(pSourceVar)
 CP A
 RET
AFVCheckBranch:
 POP HL
 POP BC
 LD D,0
 LD E,(HL)
 JR NC,AFVCheckBranch2
 INC HL
 INC HL
AFVCheckBranch2:
 ADD HL,DE
 LD E,4
 ADD HL,DE
 LD E,(HL)
 INC HL
 LD D,(HL)
 DEC HL
 EX DE,HL
 LD A,H
 OR L
 JR Z,AFVNotFound
 CALL VarPointerToBankAndAddress
 LD (VarsBank),A
 CALL SetVarsMemBank
 PUSH BC
 PUSH HL
 JR AFVNext
AFVNotFound:
 LD HL,(pSourceVar)
 OR 0xFF
 RET

; Store variable in the next free spot
; On entry HL points to variable name in source code,
; B holds the variable name length,
; A the high byte and DE the lowest bytes of the value
; Variable must fit inside the variable bank
; otherwise go to new bank.
; Return zero if variable already exist
; Return carry if out of memory
AssStoreVariable:
 PUSH AF
 PUSH DE
 PUSH HL
 LD A,(ModeFlag)
 BIT 4,A
 JR Z,ASVFirstVarExist
 RES 4,A
 LD (ModeFlag),A
 CALL VarsGoToStartBank
 LD HL,VarsStartAddr
 JR ASVStoreVar
ASVFirstVarExist:
 CALL AssFindVariable
 JR NZ,ASVStorePointer
 POP HL
 POP DE
 POP AF
 CP A
 RET
ASVStorePointer:
 PUSH DE
 LD HL,(pNextVar)
 CALL VarPointerToBankAndAddress
 CALL SetVarsMemBank
 EX DE,HL
 LD HL,VarsLastAddr
 AND A
 SBC HL,DE
 LD A,B
 ADD A,8
 LD D,0
 LD E,A
 SBC HL,DE
 POP DE
 LD HL,(pNextVar)
 JR NC,ASVStorePointer2
 CALL VarPointerToBankAndAddress
 INC A
 LD HL,VarsStartAddr
 CALL BankAndAddressToVarPointer
 JR NC,ASVStorePointer2
 POP HL
 POP DE
 POP AF
 RET
ASVStorePointer2:
 LD A,(VarsBank)
 CALL SetVarsMemBank
 EX DE,HL
 LD (HL),E
 INC HL
 LD (HL),D
 EX DE,HL
 CALL VarPointerToBankAndAddress
 LD (VarsBank),A
 CALL SetVarsMemBank
ASVStoreVar:
 LD (HL),B
 INC HL
 POP DE
 PUSH DE
 EX DE,HL
 PUSH BC
 CALL StrNCopy
 POP BC
 PUSH DE
 POP IX
 POP HL
 POP DE
 POP AF
 LD (IX+0),E
 LD (IX+1),D
 LD (IX+2),A
 XOR A
 LD (IX+3),A
 LD (IX+4),A
 LD (IX+5),A
 LD (IX+6),A
 PUSH HL
 PUSH IX
 POP HL
 LD D,0
 LD E,7
 ADD HL,DE
 LD A,(VarsBank)
 CALL BankAndAddressToVarPointer
 LD (pNextVar),HL
 POP HL
 OR 0xFF
 RET

; Parse any spaces, HL points to next non-empty space on return
; BC, DE, IX, IY and shadow registers are untouched
AssParseSpaces:
 LD HL,(pParserNextSymbol)
AssPSNext:
 LD A,(HL)
 INC HL
 CP 32
 JR Z,AssPSNext
 DEC HL
 LD (pParserNextSymbol),HL
 RET

; Go to next line, return carry if at EOF (A=0)
; or if there are more non comment chars on line (A=0xFF)
; If not, HL holds address to next symbol on return
; BC, DE, IX, IY and shadow registers are untouched
AssGoToNL:
 LD HL,(pParserNextSymbol)
AssGTNLNext:
 LD A,(HL)
 INC HL
 CP ';'
 JR Z,AssGTNLComment
 CP 32
 JR Z,AssGTNLNext
 JR NC,AssGTNLNextError
AssGTNLEOL:
 AND A
 SCF
 RET Z
 LD (pParserNextSymbol),HL
 LD (pParserCurrentLine),HL
 LD A,(HL)
 AND A
 RET NZ
 CALL SourceNextBankActive
 LD A,0
 RET C
 LD HL,SourceStartAddr
 LD (pParserNextSymbol),HL
 LD (pParserCurrentLine),HL
 RET
AssGTNLComment:
 LD A,(HL)
 INC HL
 CP 32
 JR NC,AssGTNLComment
 JR AssGTNLEOL
AssGTNLNextError:
 LD A,0xFF
 SCF
 RET

; Go to first symbol on next non empty line
; Return carry if at EOF
; If not, HL is set to first symbol on the non empty line
; BC, DE, IX, IY and shadow registers are untouched
AssParseEmptyLines:
 LD HL,(pParserNextSymbol)
AssPELNextSymbol:
 LD A,(HL)
 INC HL
 CP 32
 JR Z,AssPELNextSymbol
 DEC HL
 AND A
 JR Z,AssPELEOB
 CP ';'
 JR Z,AssPELNewLine
 CP 13
 JR NZ,AssPELNonEmpty
AssPELNewLine:
 CALL AssGoToNL
 RET C
 JR AssPELNextSymbol
AssPELNonEmpty:
 LD HL,(pParserCurrentLine)
 LD (pParserNextSymbol),HL
 AND A
 RET
AssPELEOB:
 CALL SourceNextBankActive
 RET C
 LD HL,SourceStartAddr
 LD (pParserNextSymbol),HL
 LD (pParserCurrentLine),HL
 JR AssPELNextSymbol

; Parse variable name and go to last char + 1
; Return carry if not a variable
; If a variable, HL points to the name first char
; and B holds the name length. The length may be from 3 to any
; DE, IX and IY not affected
AssParseVarName:
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CALL IsLetter
 RET C
 LD B,0
AssParseVarNameNext:
 INC B
 INC HL
 LD A,(HL)
 CALL IsLetterOrNumber
 JR NC,AssParseVarNameNext
 LD A,B
 CP 3
 RET C
 PUSH DE
 EX DE,HL
 LD HL,(pParserNextSymbol)
 EX DE,HL
 LD (pParserNextSymbol),HL
 EX DE,HL
 POP DE
 RET

; Parse label and go to char after the ':'
; Return carry if not a label
; If a label, HL points to the label first char
; and B holds the label length. The length may be from 3 to any
; IX and IY not affected
AssParseLabel:
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CALL IsLetter
 RET C
 LD B,0
AssParseLabelNext:
 INC B
 INC HL
 LD A,(HL)
 CALL IsLetterOrNumber
 JR NC,AssParseLabelNext
 CP ':'
 SCF
 RET NZ
 INC HL
 LD A,B
 CP 3
 RET C
 EX DE,HL
 LD HL,(pParserNextSymbol)
 EX DE,HL
 LD (pParserNextSymbol),HL
 EX DE,HL
 AND A
 RET

; Parse variable assignment and go to first char of number/expression
; Return carry if not a variable assignment
; If a variable assignment, HL points to the variable name first char
; and B holds the string length. The length may be from 3 to any
; IX and IY not affected
AssParseVarAssign:
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CALL IsLetter
 RET C
 LD B,0
AssPVANext:
 INC B
 INC HL
 LD A,(HL)
 CALL IsLetterOrNumber
 JR NC,AssPVANext
 CP 32
 SCF
 RET NZ
 LD A,B
 CP 3
 RET C
AssPVASkipSpaces1:
 INC HL
 LD A,(HL)
 CP 32
 JR Z,AssPVASkipSpaces1
 CP '='
 JR Z,AssPVASkipSpaces2
 LD DE,StrEqu
 CALL AssParseString
 JR NZ,AssPVAError
 DEC HL
AssPVASkipSpaces2:
 INC HL
 LD A,(HL)
 CP 32
 SCF
 RET NZ
AssPVASkipSpaces3:
 INC HL
 LD A,(HL)
 CP 32
 JR Z,AssPVASkipSpaces3
 EX DE,HL
 LD HL,(pParserNextSymbol)
 EX DE,HL
 LD (pParserNextSymbol),HL
 EX DE,HL
 AND A
 RET
AssPVAError:
 SCF
 RET

; Parse an expression
; on fail (error/no expression found), return carry
; No valid expression returns error code in A
; No expression found returns A = 0
; otherwise return value spec in A, value in ExprResult
; Value spec: Bit 4 = 1 for value not contained in word
;             Bit 5 = 1 for negative, signed number
;             Bit 6 = 0 for byte, 1 for not contained in byte
; On non carry return, ExprFlags bit 0 = 1
; if whole expression is in brackets
AssParseExpression:
 LD (ExprSP),SP
 XOR A
 LD (ExprFlags),A
 LD HL,(pParserNextSymbol)
 LD (pExprStart),HL
 LD (pExprLast),HL
 INC A
 PUSH AF
AssPENextValue:
 POP AF
 PUSH AF
 AND 7
 CP 2
 JR NZ,AssPEReadValue
 LD HL,(pParserNextSymbol)
 CALL AssSkipSpaces
 CP '+'
 JP Z,AssPEValueNotFound
 CP '-'
 JP Z,AssPEValueNotFound
AssPEReadValue:
 CALL AssParsePrefix
 LD E,A ; prefix number
 CALL AssParseNumberOrChar
 LD A,0 ; sign byte
 LD D,A ; high byte
 JR NC,AssPEReadValueDone
 CALL AssParseVarName
 JR C,AssPELookForBracket
 LD A,(ModeFlag)
 BIT 2,A
 JP Z,AssPEValueFound
 PUSH DE
 CALL AssFindVariable
 PUSH DE
 POP BC
 POP DE
 LD D,A
 LD A,ErrorVariableNotFound
 JP NZ,AssPEError
 LD A,D
 SLA A
 CCF
 LD A,0xFF
 ADC A,0
AssPEReadValueDone:
 LD (ExprValue2),BC
 LD (ExprValue2Sign),A
 LD A,D
 LD (ExprValue2High),A
 BIT 0,E
 JR Z,AssPEValueFound
 BIT 1,E
 JR Z,AssPEPrefixWasInvert
 CALL AssPENegateValue2
 JP C,AssPEError
 JR AssPEValueFound
AssPEPrefixWasInvert:
 CALL AssPEInvertValue2
 JR AssPEValueFound
AssPELookForBracket:
 LD A,E
 LD E,0x21
 BIT 0,A
 JR Z,AssPELookForBracketStart
 SET 7,E
 BIT 1,A
 JR Z,AssPELookForBracketStart
 SET 3,E
AssPELookForBracketStart:
 LD A,(HL)
 CP '('
 JR NZ,AssPEValueNotFound
 INC HL
 CALL AssSkipSpaces
 LD (pParserNextSymbol),HL
 POP AF
 PUSH AF
 DEC A
 LD A,E
 PUSH AF
 JP NZ,AssPENextValue
 LD A,(ExprFlags)
 SET 0,A
 LD (ExprFlags),A
 JP AssPENextValue
AssPEValueNotFound:
 POP AF
 AND 1
 JP NZ,AssPENoExpressionFound
 POP HL
 LD (ExprValue2),HL
 POP HL
 LD (ExprValue2High),HL
 LD A,0x41
 LD (ExprSpec),A
 LD HL,(pExprLast)
 LD (pParserNextSymbol),HL
 JP AssPEEndOfExpression
AssPEValueFound:
 LD HL,(pParserNextSymbol)
 LD (pExprLast),HL
 CALL AssParseOperator
 LD (ExprSpec),A
 JR NC,AssPEOperatorFound
 LD A,0x41
 LD (ExprSpec),A
AssPEOperatorFound:
 LD A,(ExprSpec)
 CP 0x41
 JP Z,AssPEEndOfExpression
 CP 0x61
 JP Z,AssPEEndOfBracket
 LD E,A
 LD A,(ExprFlags)
 RES 1,A
 LD (ExprFlags),A
 POP AF
 PUSH AF
 CP 1
 JR Z,AssPEWithholdCalculation
 CP 0x21
 JR Z,AssPEWithholdCalculation
 LD D,A
 AND 6
 LD C,A
 LD A,E
 AND 6
 CP C
 JR C,AssPEWithholdCalculation
 JR NZ,AssPEDoOperation
 CP 6
 JR NZ,AssPEDoOperation
 LD A,D
 AND 0x18
 LD C,A
 LD A,E
 AND 0x18
 CP C
 JR NC,AssPEDoOperation
AssPEWithholdCalculation:
 LD HL,(ExprValue2High)
 PUSH HL
 LD HL,(ExprValue2)
 PUSH HL
 LD A,(ExprSpec)
 PUSH AF
 JP AssPENextValue
AssPEDoOperation:
 POP AF
 POP HL
 LD (ExprValue1),HL
 POP HL
 LD (ExprValue1High),HL
 LD E,A
 LD A,(ModeFlag)
 BIT 2,A
 LD A,E
 JP Z,AssPEOperatorFound
 CALL AssPECalculate
 JP C,AssPEError
 JP AssPEOperatorFound
AssPEEndOfBracket:
 POP AF
 PUSH AF
 CP 1
 JR NZ,AssPEEOBTestForStartOfBracket
 LD HL,ExprFlags
 RES 1,(HL)
 LD HL,(pExprLast)
 LD (pParserNextSymbol),HL
 JR AssPEReturnResult
AssPEEOBTestForStartOfBracket:
 LD HL,ExprFlags
 SET 1,(HL)
 BIT 0,A
 JP Z,AssPEDoOperation
 POP AF
 BIT 7,A
 JP Z,AssPEValueFound
 BIT 3,A
 JR Z,AssPEInvertBracket
 CALL AssPENegateValue2
 JP NC,AssPEValueFound
 LD SP,(ExprSP)
 RET
AssPEInvertBracket:
 CALL AssPEInvertValue2
 JP AssPEValueFound
AssPEEndOfExpression:
 POP AF
 PUSH AF
 LD E,A
 AND 0x7F
 CP 0x21
 JR Z,AssPENoExpressionFound
 CP 1
 JP NZ,AssPEDoOperation
AssPEReturnResult:
 POP AF
 LD HL,ExprFlags
 SRL (HL)
 JR C,AssPERRBracketFlagFound
 RES 0,(HL)
AssPERRBracketFlagFound:
 LD A,(ModeFlag)
 BIT 2,A
 JR NZ,AssPERRSecondRun
 LD SP,(ExprSP)
 XOR A
 RET
AssPERRSecondRun:
 LD BC,4
 LD HL,ExprValue2
 LD DE,ExprResult
 LDIR
 DEC HL
 LD A,(HL)
 AND A
 JR Z,AssPERRSignTested
 SET 5,C ; sign flag
 LD B,A ; sign byte
AssPERRSignTested:
 DEC HL
 LD A,(HL)
 CP B
 JR NZ,AssPERRNotWord
 DEC HL
 LD A,(HL)
 CPL
 AND B
 AND 0x80 
 JR NZ,AssPERRNotWord
 LD A,(HL)
 CP B
 JR NZ,AssPERRNotByte
 DEC HL
 LD A,(HL)
 CPL
 AND B
 AND 0x80
 JR NZ,AssPERRNotByte
 LD A,C
 RET
AssPERRNotWord:
 SET 4,C
 SET 6,C
 LD A,C
 RET
AssPERRNotByte:
 SET 6,C
 LD A,C
 RET
AssPENoExpressionFound:
 LD HL,(pExprStart)
 LD (pParserNextSymbol),HL
 LD SP,(ExprSP)
 XOR A
 SCF
 RET
AssPEOverflowError:
 LD A,ErrorOverflowInExpression
AssPEError:
 LD SP,(ExprSP)
 SCF
 RET


; Calculate operation with operator specifier in A
; Return carry if the operation is invalid
; or there is overflow, error code in A
AssPECalculate:
 SRL A
 LD (ExprOp),A
 AND A
 JP Z,AssPEMultiplication
 CP 4 ; Division
 JP Z,AssPEDivision
 CP 8 ; Modulo, uses same routine
 JP Z,AssPEDivision
 CP 1
 JP Z,AssPEAddition
 CP 5
 JP Z,AssPESubtraction
 CP 2
 JP Z,AssPEShiftLeft
 CP 6
 JP Z,AssPEShiftRight
 CP 3
 JP Z,AssPEAnd
 CP 7
 JP Z,AssPEXor
 JP AssPEOr


; Copy result from ExprResult to ExprValue2 and return
AssPECopyFromResult:
 LD DE,ExprResult
 JR AssPECopyToValue2
; Copy result from ExprValue1 to ExprValue2 and return
AssPECopyFromValue1:
 LD DE,ExprValue1
AssPECopyToValue2:
 LD HL,ExprValue2
 LD B,4
AssPECopyNextByte:
 LD A,(DE)
 LD (HL),A
 INC HL
 INC DE
 DJNZ AssPECopyNextByte
 AND A
 RET


AssPENegateResult:
 LD HL,ExprResult
 JR AssPENegate
AssPENegateValue1:
 LD HL,ExprValue1
 JR AssPENegate
AssPENegateValue2:
 LD HL,ExprValue2
AssPENegate:
 LD B,4
 SCF
AssPENegateByte:
 LD A,(HL)
 CPL
 ADC A,0
 LD (HL),A
 INC HL
 DJNZ AssPENegateByte
 DEC HL
AssPECalculateExit:
 AND A
 RET Z
 INC A
 SCF
 LD A,ErrorOverflowInExpression
 RET NZ
 DEC HL
 BIT 7,(HL)
 RET Z
 CCF
 RET

AssPEInvertValue2:
 LD HL,ExprValue2
 LD B,4
AssPEInvertNext:
 LD A,(HL)
 CPL
 LD (HL),A
 INC HL
 DJNZ AssPEInvertNext
 RET

AssPEAddition:
 LD DE,ExprValue1
 LD HL,ExprValue2
 AND A
 LD B,4
AssPEAddByte:
 LD A,(DE)
 ADC A,(HL)
 LD (HL),A
 INC DE
 INC HL
 DJNZ AssPEAddByte
 DEC HL
 JP AssPECalculateExit

AssPESubtraction:
 CALL AssPENegateValue2
 JP AssPEAddition

AssPEMultiplication:
 LD DE,ExprValue1Sign
 LD HL,ExprValue2Sign
 LD A,(DE)
 XOR (HL)
 PUSH AF
 LD A,(DE)
 INC A
 CALL Z,AssPENegateValue1
 LD A,(ExprValue2Sign)
 INC A
 CALL Z,AssPENegateValue2
 LD B,4
 LD HL,ExprResult
 XOR A
AssPEMulResetResult:
 LD (HL),A
 INC HL
 DJNZ AssPEMulResetResult
 LD HL,ExprValue2Sign
 LD B,4
AssPEMulFactorCompare:
 LD A,(DE)
 CP (HL)
 JR NZ,AssPEMulSelectOrder
 DEC DE
 DEC HL
 DJNZ AssPEMulFactorCompare
 SCF
AssPEMulSelectOrder:
 LD DE,ExprValue1
 LD HL,ExprValue2
 JR C,AssPEMulOrderSelected
 EX DE,HL
; DE points to the lowest factor
AssPEMulOrderSelected:
 INC DE
 INC DE
 LD A,(DE)
 AND A
 JR NZ,AssPEMulOverflow
 INC DE
 LD A,(DE)
 AND A
 JR Z,AssPEMulFactorOk
AssPEMulOverflow:
 POP AF
 SCF
 LD A,ErrorOverflowInExpression
 RET
AssPEMulFactorOk:
 DEC DE
 DEC DE
 DEC DE
AssPEMulShift1:
; test if lowest factor is 0
 LD A,(DE)
 LD C,A
 INC DE
 LD A,(DE)
 OR C
 JR Z,AssPEMulApplySign
; shift low factor one bit right
 LD A,(DE)
 AND A
 RRA
 LD (DE),A
 DEC DE
 LD A,(DE)
 RRA
 LD (DE),A
 JR NC,AssPEMulShiftHigh
; add adjusted high factor to result
 PUSH HL
 PUSH DE
 LD DE,ExprResult
 AND A
 LD B,3
AssPEMulAddNextByte:
 LD A,(DE)
 ADC A,(HL)
 LD (DE),A
 INC DE
 INC HL
 DJNZ AssPEMulAddNextByte
 POP DE
 POP HL
 JR C,AssPEMulOverflow
AssPEMulShiftHigh:
; shift high factor 1 bit left
 AND A
 RL (HL)
 INC HL
 RL (HL)
 INC HL
 RL (HL)
 JR C,AssPEMulOverflow
 DEC HL
 DEC HL
 JR AssPEMulShift1
AssPEMulApplySign:
 POP AF
 AND A
 JP Z,AssPECopyFromResult
 CALL AssPENegateResult
 RET C
 JP AssPECopyFromResult
 

; Division (stored in result) or Modulo (stored in value 1)
; ExprOp determines the operation being done (4: division, 8: modulo)
AssPEDivision:
 LD HL,ExprValue2
 XOR A
 LD B,3
AssPEDivIsDenominator0:
 OR (HL)
 JR NZ,AssPEDivLegal
 INC HL
 DJNZ AssPEDivIsDenominator0
 LD A,ErrorDivisionByZero
 SCF
 RET
AssPEDivLegal:
 LD DE,ExprValue1Sign
 LD HL,ExprValue2Sign
 LD A,(DE)
 LD B,A
 XOR (HL)
 LD C,A
 PUSH BC
 LD A,(DE)
 INC A
 CALL Z,AssPENegateValue1
 LD A,(ExprValue2Sign)
 INC A
 CALL Z,AssPENegateValue2
 LD B,4
 LD HL,ExprResult
 XOR A
AssPEDivResetResult:
 LD (HL),A
 INC HL
 DJNZ AssPEDivResetResult
 LD C,0
AssPEDivLeftshiftValue2OneBit:
 CALL AssPEDivCompareValues
 JR C,AssPEDivLeftShiftDone
 INC C
 LD HL,ExprValue2
 SLA (HL)
 INC HL
 RL (HL)
 INC HL
 RL (HL)
 INC HL
 RL (HL)
 JR AssPEDivLeftshiftValue2OneBit
AssPEDivLeftShiftDone:
 LD B,C
 SRL B
 SRL B
 SRL B
 ;B holds number of bytes the divisor was shifted left
 LD A,C
 AND 7
 INC A
 LD C,0
 SCF
AssPEDivNextResultBitPosition:
 RL C
 DEC A
 JR NZ,AssPEDivNextResultBitPosition
 ;C holds bit at correct position for next add to result
 PUSH BC
 XOR A
 EX AF,AF' ; A' holds counter of number of leftshifts done on the divident
AssPEDivCompare:
 CALL AssPEDivCompareValues
 JR NC,AssPEDivSubtract
AssPEDivLeftShiftDivident:
 POP BC
 RRC C
 JR NC,AssPEDivLSDShift
 LD A,B
 AND A
 JR NZ,AssPEDivLSDDecB
 LD A,(ExprOp)
 CP 4
 JR NZ,AssPEDivModuloExit
 POP BC
 INC C
 JP NZ,AssPECopyFromResult
 CALL AssPENegateResult
 RET C
 JP AssPECopyFromResult
AssPEDivModuloExit:
 EX AF,AF'
AssPEDivMEShiftNext:
 AND A
 JR Z,AssPEDivMEShiftDone
 LD HL,ExprValue1Sign
 SRL (HL)
 DEC HL
 RR (HL)
 DEC HL
 RR (HL)
 DEC HL
 RR (HL)
 DEC A
 JR AssPEDivMEShiftNext
AssPEDivMEShiftDone:
 POP BC
 INC B
 JP NZ,AssPECopyFromValue1
 CALL AssPENegateValue1
 RET C
 JP AssPECopyFromValue1
AssPEDivLSDDecB:
 DEC B
AssPEDivLSDShift:
 EX AF,AF'
 INC A
 EX AF,AF'
 PUSH BC
 LD HL,ExprValue1
 SLA (HL)
 INC HL
 RL (HL)
 INC HL
 RL (HL)
 INC HL
 RL (HL)
 JR AssPEDivCompare
AssPEDivSubtract:
 LD DE,ExprValue1
 LD HL,ExprValue2
 LD B,3
 AND A
AssPEDivSubtractNextByte:
 LD A,(DE)
 SBC A,(HL)
 LD (DE),A
 INC DE
 INC HL
 DJNZ AssPEDivSubtractNextByte
 LD HL,ExprResult
 POP BC
 PUSH BC
 LD D,0
 LD E,B
 ADD HL,DE
 LD A,C
 OR (HL)
 LD (HL),A
 JP AssPEDivCompare
; Compare value1 to value2, return carry for value2 > value1
AssPEDivCompareValues:
 LD HL,ExprValue2Sign
 LD A,(HL)
 AND A
 SCF
 RET NZ
 DEC HL
 LD DE,ExprValue1High
 LD B,3
AssPEDivCompareNext:
 LD A,(DE)
 CP (HL)
 RET NZ
 DEC HL
 DEC DE
 DJNZ AssPEDivCompareNext
 AND A
 RET


AssPEShiftLeft:
 LD HL,ExprValue2Sign
 XOR A
 OR (HL)
 DEC HL
 OR (HL)
 DEC HL
 OR (HL)
 LD A,ErrorInvalidArgument
 SCF
 RET NZ
 DEC HL
 LD A,(HL)
 LD C,A
 CP 25
 CCF
 LD A,ErrorInvalidArgument
 RET C
 LD A,C
 AND 0xF8
 JR Z,AssPESLShiftBits
AssPESLShiftBytes:
 LD HL,ExprValue1
 LD B,(HL)
 XOR A
 LD (HL),A
 INC HL
 LD A,(HL)
 LD (HL),B
 INC HL
 LD (HL),A
 LD A,C
 SUB 8
 LD C,A
 AND 0xF8
 JR NZ,AssPESLShiftBytes
AssPESLShiftBits:
 LD A,C
 AND A
 JR Z,AssPESLShiftDone
 LD HL,ExprValue1
 XOR A
 LD D,3
AssPESLSBNextByte:
 LD B,C
 LD E,0
AssPESLShiftNextBit:
 SLA (HL)
 RL E
 DJNZ AssPESLShiftNextBit
 OR (HL)
 LD (HL),A
 INC HL
 LD A,E
 DEC D
 JR NZ,AssPESLSBNextByte
AssPESLShiftDone:
 LD A,(ExprValue1High)
 RLCA
 AND 1
 DEC A
 CPL
 LD (ExprValue1Sign),A
 JP AssPECopyFromValue1

AssPEShiftRight:
 LD HL,ExprValue2Sign
 XOR A
 OR (HL)
 DEC HL
 OR (HL)
 DEC HL
 OR (HL)
 LD A,ErrorInvalidArgument
 SCF
 RET NZ
 DEC HL
 LD A,(HL)
 LD C,A
 CP 25
 CCF
 LD A,ErrorInvalidArgument
 RET C
 LD B,C
 SRL B
 SRL B
 SRL B
 LD A,C
 AND 7
 LD C,A
 JR Z,AssPESRShiftBytes
 PUSH BC
 LD HL,ExprValue1High
 LD B,C
 XOR A
AssPESRShiftNextBitArithmic:
 SRA (HL)
 RRA
 DJNZ AssPESRShiftNextBitArithmic
 DEC HL
 LD D,2
AssPESRSBNextByte:
 LD B,C
 LD E,0
AssPESRShiftNextBit:
 SRL (HL)
 RR E
 DJNZ AssPESRShiftNextBit
 OR (HL)
 LD (HL),A
 DEC HL
 LD A,E
 DEC D
 JR NZ,AssPESRSBNextByte
 POP BC
AssPESRShiftBytes:
 LD A,B
 AND A
 JP Z,AssPECopyFromValue1
 LD HL,ExprValue1Sign
 LD A,(HL)
 DEC HL
 LD E,(HL)
 LD (HL),A
 DEC HL
 LD A,(HL)
 LD (HL),E
 DEC HL
 LD (HL),A
 JR AssPESRShiftBytes


AssPEAnd:
 LD B,4
 LD DE,ExprValue1
 LD HL,ExprValue2
AssPEAndNext:
 LD A,(DE)
 AND (HL)
 LD (HL),A
 INC DE
 INC HL
 DJNZ AssPEAndNext
 RET

AssPEXor:
 LD B,4
 LD DE,ExprValue1
 LD HL,ExprValue2
AssPEXorNext:
 LD A,(DE)
 XOR (HL)
 LD (HL),A
 INC DE
 INC HL
 DJNZ AssPEXorNext
 RET

AssPEOr:
 LD B,4
 LD DE,ExprValue1
 LD HL,ExprValue2
AssPEOrNext:
 LD A,(DE)
 OR (HL)
 LD (HL),A
 INC DE
 INC HL
 DJNZ AssPEOrNext
 RET

; Skip any spaces in source code pointed to by HL
; HL points to next non-space on return
AssSkipSpaces:
 LD A,(HL)
 CP 32
 RET NZ
 INC HL
 JR AssSkipSpaces

; Parse operator in expression and return specifier in A
; Return carry if no operator is found
AssParseOperator:
 XOR A
 LD E,A
 LD D,A
 LD HL,(pParserNextSymbol)
 CALL AssSkipSpaces
 CP '*'
 JR Z,AssPOFound
 INC E
 CP '/'
 JR Z,AssPOFound
 INC E
 CP '%'
 JR Z,AssPOFound
 INC D
 LD E,0
 CP '+'
 JR Z,AssPOFound
 INC E
 CP '-'
 JR Z,AssPOFound
 INC D
 LD E,0
 CP '<'
 JR NZ,AssPOTestForShiftRight
 INC HL
 LD A,(HL)
 CP '<'
 JR Z,AssPOFound
 SCF
 RET
AssPOTestForShiftRight:
 INC E
 CP '>'
 JR NZ,AssPOTestForLogical
 INC HL
 LD A,(HL)
 CP '>'
 JR Z,AssPOFound
 SCF
 RET
AssPOTestForLogical:
 INC D
 LD E,0
 CP '&'
 JR Z,AssPOFound
 INC E
 CP '^'
 JR Z,AssPOFound
 INC E
 CP '|'
 JR Z,AssPOFound
 CP ')'
 JR Z,AssPOBracketEnd
 SCF
 RET
AssPOBracketEnd:
 INC HL
 CALL AssSkipSpaces
 LD (pParserNextSymbol),HL
 LD A,0x61
 AND A
 RET
AssPOFound:
 INC HL
 CALL AssSkipSpaces
 LD (pParserNextSymbol),HL
 LD A,E
 SLA A
 SLA A
 ADD A,D
 SLA A
 RET

 
; Case insensitive compare parse of given string
; Upon entry HL points to string in source
; and DE points to a 0 determined capital letter string
; Return NZ if strings don't match, HL is then unchanged
; Otherwise HL points to char after string
; BC is unaffected
AssParseString:
 PUSH HL
 DEC HL
 DEC DE
AssPSNextChar:
 INC HL
 INC DE
 LD A,(DE)
 AND A
 JR Z,AssPSAtEnd
 LD A,(HL)
 CP 97
 JR C,AssPSCharCmp
 CP 123
 JR NC,AssPSCharCmp
 SUB 32
AssPSCharCmp:
 EX DE,HL
 CP (HL)
 EX DE,HL
 JR Z,AssPSNextChar
 POP HL
 RET
AssPSAtEnd:
 POP DE
 RET

; Parse argument element and return in A (0 if non found)
; Searches for number, variable, constant string (1-22)
; Or 8 bit register in that order (to prevent conflict)
; Any expression value or register number returned in BC
; Return carry for invalid expression or undefined variable,
; error code in A.
AssParseArgElement:
 LD HL,(pParserNextSymbol)
 PUSH HL
 CALL AssParseExpression
 LD BC,(ExprResult)
 POP HL
 JR NC,AssPAETestForOverflow
 AND A
 SCF
 RET NZ
 JR AssPAETestString
AssPAETestForOverflow:
 BIT 4,A
 JR Z,AssPAETestForSign
 LD A,ErrorInvalidNumber
 SCF
 RET
AssPAETestForSign:
 SET 7,A
 LD E,A
 LD A,(HL)
 CP '+'
 JR Z,AssPAEIsPrefix
 CP '-'
 JR Z,AssPAEIsPrefix
 LD A,(ExprFlags)
 AND A
 BIT 0,A
 LD A,E
 RET Z
 PUSH HL
 LD HL,(pParserNextSymbol)
 CALL AssSkipSpaces
 POP HL
 CP ','
 JR Z,AssPAEIndirectAdressing
 CP ';'
 JR Z,AssPAEIndirectAdressing
 CP 32
 JR C,AssPAEIndirectAdressing
 LD A,E
 RET
AssPAEIndirectAdressing:
 INC HL
 CALL AssSkipSpaces
 LD (pParserNextSymbol),HL
 LD A,2
 AND A
 RET
AssPAEIsPrefix:
 LD A,E
 SET 1,A
 RET
AssPAETestString:
 LD DE,ArgStrings
 LD C,0
AssPAETestNextString:
 PUSH DE
 LD HL,(pParserNextSymbol)
 INC C
 LD B,3
AssPAETestNextChar:
 LD A,(DE)
 AND A
 JR Z,AssPAEStringMatch
 LD A,(HL)
 CP 97
 JR C,AssPAETestCapitalLetter
 CP 123
 JR NC,AssPAETestCapitalLetter
 SUB 32
AssPAETestCapitalLetter:
 EX DE,HL
 CP (HL)
 EX DE,HL
 JR NZ,AssPAEStringMismatch
 INC DE
 INC HL
 DJNZ AssPAETestNextChar
AssPAEStringMatch:
 POP DE
 LD (pParserNextSymbol),HL
 LD A,C
 RET
AssPAEStringMismatch:
 POP DE
 INC DE
 INC DE
 INC DE
 LD A,C
 CP 22
 JR NZ,AssPAETestNextString
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 EX DE,HL
 LD HL,Reg8Names
 LD B,8
 LD C,0
 CP 97
 JR C,AssPAETestNextReg
 CP 123
 JR NC,AssPAETestNextReg
 SUB 32
AssPAETestNextReg:
 CP (HL)
 JR Z,AssPAERegMatch
 INC HL
 INC C
 DJNZ AssPAETestNextReg
 XOR A
 RET
AssPAERegMatch:
 LD B,0
 LD A,C
 CP 6
 LD A,B
 RET Z
 EX DE,HL
 INC HL
 LD (pParserNextSymbol),HL
 LD A,0x81
 AND A
 RET

; Compare of given strings, Return Z if match
; Upon entry HL points to capital letter string in buffer
; and DE points to a capital letter string of max N chars (N in B),
; either string is 0 determined at end if string is shorter than max
; HL is preserved
AssCompareStringN:
 PUSH HL
AssCSNNextChar:
 LD A,(DE)
 CP (HL)
 JR NZ,AssCSNExit
 AND A
 JR Z,AssCSNExit
 INC HL
 INC DE
 DEC B
 JR NZ,AssCSNNextChar
AssCSNExit:
 POP HL
 RET

; Return carry if symbol in A is not a letter
; Only flags are affected
IsLetter:
 CP 65
 RET C
 CP 91
 CCF
 RET NC
 CP 97
 RET C
 CP 123
 CCF
 RET

; Return carry if symbol in A is not a number
; Only flags are affected
IsNumber:
 CP 48
 RET C
 CP 58
 CCF
 RET

; Return carry if symbol in A is not a letter or number
; Only flags are affected
IsLetterOrNumber:
 CP 48
 RET C
 CP 58
 CCF
 RET NC
 CP 65
 RET C
 CP 91
 CCF
 RET NC
 CP 97
 RET C
 CP 123
 CCF
 RET

; convert hex digit char in A to number (0-15) in A
; return carry if not a hex digit
CharToHex:
 SUB 48
 RET C
 CP 10
 CCF
 RET NC
 SUB 7
 CP 10
 RET C
 CP 16
 CCF
 RET NC
 SUB 32
 CP 10
 RET C
 CP 16
 CCF
 RET

; convert binary digit char in A to number (0-1) in A
; return carry if not a binary digit
CharToBinary:
 SUB 48
 RET Z
 CP 1
 RET Z
 SCF
 RET

; Convert decimal digit char in A to number (0-9) in A
; Return carry if not a decimal digit
CharToDecimal:
 SUB 48
 RET C
 CP 10
 CCF
 RET

; Parse a hex, decimal or binary number or a single char
; on fail, return carry and leave parse pointer untouched
; otherwise return prefix spec in A and value in BC
; Value in BC is positive, unmodified by prefix
; Preserves DE, IX and IY
AssParseNumberOrChar:
 CALL AssParseSingleChar
 RET NC
 JP AssParseNumber

; Parse a single char in '' (byte)
; on fail, return carry and leave parse pointer untouched
; otherwise return number spec in A and value in BC
; Preserves DE, IX and IY
AssParseSingleChar:
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CP 0x27
 SCF
 RET NZ
 INC HL
 LD A,(HL)
 CP 32
 RET C
 CP 128
 CCF
 RET C
 LD C,A
 INC HL
 LD A,(HL)
 CP 0x27
 SCF
 RET NZ
 INC HL
 LD (pParserNextSymbol),HL
 XOR A
 LD B,A
 RET

;Parse a prefix and return id in A
; A = 0 : No prefix
;     1 : ~
;     2 : +
;     3 : -
AssParsePrefix:
 PUSH DE
 PUSH HL
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 INC HL
 LD E,3
 CP '-'
 JR Z,APPPastPrefix
 DEC E
 CP '+'
 JR Z,APPPastPrefix
 DEC E
 CP '~'
 JR Z,APPPastPrefix
 DEC E
 JR APPReturn
APPPastPrefix:
 LD (pParserNextSymbol),HL
APPReturn:
 LD A,E
 POP HL
 POP DE
 RET


; Parse a hex or decimal number, on fail
; return carry and leave parse pointer untouched
; otherwise return value in BC
; Preserves DE, IX and IY
AssParseORGArgument:
 LD HL,(pParserNextSymbol)
 LD A,(HL)
 CP '$'
 JR Z,APORGHex
 CP '#'
 JR Z,APORGHex
 CP '0'
 JR NZ,APORGDecimal
 INC HL
 LD A,(HL)
 CP 'x'
 JR Z,APORGHex
 DEC HL
APORGDecimal:
 CALL AssParseDecimal
 RET C
 LD (pParserNextSymbol),HL
 RET
APORGBinary:
 INC HL
 CALL AssParseBinary
 RET C
 LD (pParserNextSymbol),HL
 RET
APORGHex:
 INC HL
 CALL AssParseHex
 RET C
 LD (pParserNextSymbol),HL
 RET



; Parse a hex, decimal or binary (unprefix'ed) number
; on fail, return carry and leave parse pointer untouched
; otherwise return value in BC
; Preserves DE, IX and IY
AssParseNumber:
 PUSH DE
 LD A,(HL)
 CP '%'
 JR Z,APNBinary
 CP '$'
 JR Z,APNHexOrPC
 CP '#'
 JR Z,APNHex
 CP '0'
 JR NZ,APNDecimal
 INC HL
 LD A,(HL)
 CP 'x'
 JR Z,APNHex
 DEC HL
APNDecimal:
 CALL AssParseDecimal
 JR C,APNReturnError
 JR APNReturnNumber
APNBinary:
 INC HL
 CALL AssParseBinary
 JR C,APNReturnError
 JR APNReturnNumber
APNHexOrPC:
 INC HL
 CALL AssParseHex
 JR NC,APNReturnNumber
 LD BC,(pObjectNextCode) ; Current Program counter value
 LD HL,(pParserNextSymbol)
 INC HL
 JR APNReturnNumber
APNHex:
 INC HL
 CALL AssParseHex
 JR C,APNReturnError
APNReturnNumber:
 LD (pParserNextSymbol),HL
 POP DE
 AND A
 RET
APNReturnError:
 POP DE
 RET


; Parse hex number excluding prefix '$', '#' or '0x'
; on entry HL points to first digit in source code
; return carry if number is too big or is missing
; if not, on return HL points to first symbol after number,
; A holds the number spec and BC the value
; Preserves DE, IX and IY
AssParseHex:
 PUSH DE
 XOR A
 LD D,A
 LD E,A
 LD B,A
 LD C,A
 DEC HL
 DEC D
AssParseHexNextSymbol:
 INC D
 LD A,4
 CP D
 JR NC,AssParseHexTestNext
AssParseHexError:
 POP DE
 RET
AssParseHexTestNext:
 INC HL
 LD A,(HL)
 CALL CharToHex
 JR NC,AssParseHexNextSymbol
 LD A,D
 AND A
 SCF
 JR Z,AssParseHexError
 CP 3
 JR C,AssParseHexStoreValue
 SET 6,E
AssParseHexStoreValue:
 PUSH HL
 DEC HL
 LD A,(HL)
 CALL CharToHex
 LD C,A
 DEC D
 JR Z,AssParseHexExit
 DEC HL
 LD A,(HL)
 CALL CharToHex
 SWAPNIB
 OR C
 LD C,A
 DEC D
 JR Z,AssParseHexExit
 DEC HL
 LD A,(HL)
 CALL CharToHex
 LD B,A
 DEC D
 JR Z,AssParseHexExit
 DEC HL
 LD A,(HL)
 CALL CharToHex
 SWAPNIB
 OR B
 LD B,A
AssParseHexExit:
 LD A,E
 POP HL
 POP DE
 AND A
 RET
 
; Parse binary number excluding prefix '%'
; ignore chars ' and _
; on entry HL points to first number char in source code
; return carry if number is too big or there are no digits
; if not, on return HL points to first symbol after number,
; A holds the number spec and BC the value
; Preserves DE, IX and IY
AssParseBinary:
 PUSH DE
 XOR A
 LD B,A
 LD C,A
 LD E,A
 LD D,9
 DEC HL
AssParseBinaryNextBit:
 INC HL
 LD A,(HL)
 CP 0x27
 JR Z,AssParseBinaryNextBit
 CP '_'
 JR Z,AssParseBinaryNextBit
 CALL CharToBinary
 JR C,AssParseBinaryExit
 CP 1
 CCF
 RL C
 RL B
 DEC D
 JR NZ,AssParseBinaryNextBit
 BIT 6,E
 JR NZ,AssParseBinaryError
 SET 6,E
 LD D,8
 JR AssParseBinaryNextBit
AssParseBinaryExit:
 LD A,D
 CP 9
 CCF
 LD A,E
 POP DE
 RET
AssParseBinaryError:
 POP DE
 SCF
 RET

; Parse decimal number
; on entry HL points to first digit in source code
; return carry if number is out of bounds or invalid format
; if not, on return HL points to first symbol after number,
; A holds the number spec and BC the value
; Preserves DE, IX and IY
AssParseDecimal:
 PUSH DE
 XOR A
 LD D,A
 LD E,A
 LD A,(HL)
 DEC HL
 CP '0'
 JR NZ,APDNextSymbol
 INC HL
 INC HL
 LD A,(HL)
 CALL CharToDecimal
 JP NC,APDError
 LD BC,0
 LD A,E
 POP DE
 AND A
 RET
APDNextSymbol:
 INC HL
 LD A,(HL)
 CALL CharToDecimal
 JR C,APDAtEnd
 INC D
 LD A,D
 CP 6
 JP NC,APDError
 JR APDNextSymbol
APDAtEnd:
 LD A,D
 AND A
 JP Z,APDError
 PUSH HL
 DEC HL
 LD A,E
 PUSH AF
 LD A,D
 PUSH AF
 LD A,(HL)
 CALL CharToDecimal
 DEC HL
 EX DE,HL
 LD H,0
 LD L,A
 LD (DecimalSum),HL
 POP AF
 LD HL,DecimalDigitsWord10
APDNextDigit:
 DEC A
 JR Z,APDSumDone
 PUSH AF
 LD C,(HL)
 INC HL
 LD B,(HL)
 DEC HL
 DEC HL
 DEC HL
 LD A,(DE)
 CALL CharToDecimal
 PUSH HL
 LD HL,(DecimalSum)
 INC A
APDNextAdd:
 DEC A
 JR Z,APDMulDone
 ADD HL,BC
 JR NC,APDNextAdd
 POP HL
 POP HL
 POP HL
 POP HL
 POP DE
 RET
APDMulDone:
 LD (DecimalSum),HL
 POP HL
 POP AF
 DEC DE
 JR APDNextDigit
APDSumDone:
 LD HL,(DecimalSum)
 POP AF
 LD E,A
 LD A,H
 AND A
 LD A,E
 JR Z,APDExit
 SET 6,A
APDExit:
 PUSH HL
 POP BC
 POP HL
 POP DE
 RET
APDOverflow:
 POP HL
APDError:
 POP DE
 SCF
 RET


; On entry, A holds previous block checksum (0 if none)
; HL Points to block start address and BC holds the size
; Updates checksum from block data and returns in A
CalcChecksum:
 DEC C
 INC C
 JR Z,CalcChecksumNext
 INC B
CalcChecksumNext:
 XOR (HL)
 INC HL
 DEC C
 JR NZ,CalcChecksumNext
 DJNZ CalcChecksumNext
 RET

; Output 5 digits (may be 0's in higher digits) in char codes,
; BC holds integer to be output, HL holds output address
OutputDecimalDigitsWord:
 LD DE,DecimalDigitsWord
 PUSH HL
 POP IX
 PUSH BC
 POP HL
 LD B,5
ODDWNextDigit:
 PUSH BC
 EX DE,HL
 LD C,(HL)
 INC HL
 LD B,(HL)
 INC HL
 EX DE,HL
 LD A,47
 AND A
ODDWSUBDigit:
 INC A
 SBC HL,BC
 JR NC,ODDWSUBDigit
 ADD HL,BC
 LD (IX+0),A
 INC IX
 POP BC
 DJNZ ODDWNextDigit
 RET
 
; Output 3 digits (may be 0's in higher digits) in char codes,
; C holds integer to be output, HL holds output address
OutputDecimalDigitsByte:
 LD B,3
 LD IX,DecimalDigitsByte
ODDBNextDigit:
 LD E,(IX+0)
 INC IX
 LD D,47
 LD A,C
ODDBSUBDigit:
 INC D
 SUB E
 JR NC,ODDBSUBDigit
 ADD A,E
 LD C,A
 LD (HL),D
 INC HL
 DJNZ ODDBNextDigit
 RET

; Save a .tap file executable
; Return carry if the operation fails
SaveTapFile:
 LD HL,ObjectFilename
 LD DE,TapFileFilename
 LD B,10
STFBASICFNCopy:
 LD A,(HL)
 AND A
 JR Z,STFBASICFNAppend
 LD (DE),A
 INC HL
 INC DE
 DEC B
 JR STFBASICFNCopy
STFBASICFNAppend:
 LD A,32
 LD (DE),A
 INC DE
 DJNZ STFBASICFNAppend
 LD HL,ObjectFilename
 LD DE,StrTap
 CALL AppendEndingToName
 LD IX,ObjectFilename
 LD A,'$'
 LD B,0x0E
 RST 8
 DEFB 0x9A
 PUSH AF
 LD HL,ObjectFilename
 CALL RemoveEndingFromName
 POP AF
 RET C
 PUSH AF
 XOR A
 LD (TapFileHeader),A
 LD HL,76
 LD (TapFileLength),HL
 LD (TapFileProgramLength),HL
 LD HL,10
 LD (TapFileStart),HL
 LD HL,TapFileHeader
 LD BC,17
 CALL CalcChecksum
 LD (TapFileHeaderChecksum),A
 LD HL,78
 LD (TapFileProgramBlock),HL
 LD A,(NoORG)
 LD (TapFileBlocksByte),A
 LD C,A
 LD HL,TapFileBlocksDigits
 CALL OutputDecimalDigitsByte
 CALL ObjectGoToStart
 LD HL,(EntryAddress)
 LD A,(EntryFlag)
 BIT 0,A
 JR NZ,STFBASICStoreEntry
 CALL SetObjectBankAsActive
 LD HL,(ObjectStartAddr)
STFBASICStoreEntry:
 LD (TapFileEntryAddress),HL
 PUSH HL
 POP BC
 LD HL,TapFileEntryDigits
 CALL OutputDecimalDigitsWord
 LD HL,TapFileBASIC
 LD BC,76
 LD A,0xFF
 CALL CalcChecksum
 LD (TapFileBodyChecksum),A
 POP AF
 LD IX,TapFileHeaderBlock
 LD BC,101
 PUSH AF
 RST 8
 DEFB 0x9E
 POP DE
 RET C
 PUSH DE
 CALL SetObjectBankAsActive
STFWriteNextCodeBlock:
 LD HL,(pObjectNextCode)
 LD E,(HL)
 INC HL
 LD D,(HL)
 INC HL
 LD C,(HL)
 INC HL
 LD B,(HL)
 INC HL
 LD (pObjectNextCode),HL
 LD A,B
 OR C
 JP Z,STFBlockWritten
 LD A,3
 LD (TapFileHeader),A
 PUSH BC
 POP HL
 LD (TapFileLength),HL
 INC HL
 INC HL
 LD (TapFileProgramBlock),HL
 EX DE,HL
 LD (TapFileStart),HL
 LD HL,TapFileHeader
 LD BC,17
 XOR A
 CALL CalcChecksum
 LD (TapFileHeaderChecksum),A
 POP AF
 PUSH AF
 LD IX,TapFileHeaderBlock
 LD BC,24
 RST 8
 DEFB 0x9E
 POP DE
 RET C
 PUSH DE
 LD HL,(TapFileLength)
 EX DE,HL
 LD A,0xFF
 LD (TapFileBodyChecksum),A
STFNextDataWrite:
 LD HL,(pObjectNextCode)
 PUSH HL
 POP BC
 LD H,ObjectEndHigh
 LD L,0
 AND A
 SBC HL,BC
 JR NZ,STFNDWBankOk
 CALL ObjectNextBankActive
 LD HL,ObjectStartAddr
 LD (pObjectNextCode),HL
 LD HL,0x2000
STFNDWBankOk:
 EX DE,HL
 PUSH HL
 POP BC
 AND A
 SBC HL,DE
 JR C,STFWriteRemaining
 EX DE,HL
 PUSH HL
 POP BC
 JR STFWriteData
STFWriteRemaining:
 LD DE,0
STFWriteData:
 LD HL,(pObjectNextCode)
 PUSH HL
 POP IX
 POP AF
 PUSH BC
 PUSH DE
 PUSH AF
 RST 8
 DEFB 0x9E
 POP DE
 LD A,D
 POP DE
 POP BC
 RET C
 PUSH AF
 LD HL,(pObjectNextCode)
 PUSH HL
 PUSH BC
 LD A,(TapFileBodyChecksum)
 CALL CalcChecksum
 LD (TapFileBodyChecksum),A
 POP BC
 POP HL
 ADD HL,BC
 LD (pObjectNextCode),HL
 LD A,D
 OR E
 JP NZ,STFNextDataWrite
 LD IX,TapFileBodyChecksum
 LD BC,1
 POP AF
 PUSH AF
 RST 8
 DEFB 0x9E
 POP DE
 RET C
 PUSH DE
STFBlockWritten:
 LD HL,(pObjectNextCode)
 INC HL
 INC HL
 INC HL
 LD A,L
 AND 0xFC
 LD L,A
 LD A,H
 CP ObjectEndHigh
 JR NZ,STFBWBankOk
 CALL ObjectNextBankActive
 LD HL,ObjectStartAddr
 LD (pObjectNextCode),HL
STFBWBankOk:
 LD A,(NoORG)
 DEC A
 LD (NoORG),A
 JP NZ,STFWriteNextCodeBlock
 POP AF
 RST 8
 DEFB 0x9B
 AND A
 RET

; Open file browser for load or save
; For save only directories are displayed,
; for user to choose a directory to save to
; For load also files with valid filenames are displayed,
; in order for user to select file to load
; For load return pointer to filename in IX
; or IX = 0 for no selection (break)
; Return carry in case of file system error
FileBrowse:
 CALL SetVarsBankAsActive
 LD IX,VarsStartAddr
 LD A,'.'
 LD (IX+0),A
 LD A,'/'
 LD (IX+1),A
 XOR A
 LD (IX+2),A
 LD B,%10010000
 LD C,%00110000
 LD A,(ModeFlag)
 AND 128
 OR C
 LD C,A
 LD A,'$'
 RST 8
 DEFB 0xA3
 RET C
FBReadPageOfEntries:
 PUSH AF
 XOR A
 LD (NoDirEntries),A
 DEC A
 LD (SelectedEntry),A
 POP AF
 LD IX,VarsStartAddr
FBReadNextEntry:
 PUSH AF
 PUSH IX
 RST 8
 DEFB 0xA4
 POP IX
 JR NC,FBReadOk
 POP AF
 RST 8
 DEFB 0x9B
 SCF
 RET
FBReadOk:
 AND A
 JR Z,FBListEntries
 LD A,(NoDirEntries)
 INC A
 LD C,A
 LD A,(EditAreaLines)
 SUB 2
 CP C
 JR Z,FBListEntries
 PUSH IX
 POP HL
 BIT 4,(HL)
 JR Z,FBReadFileEntry
 INC HL
FBReadDirEntryNextChar:
 LD A,(HL)
 INC HL
 AND A
 JR NZ,FBReadDirEntryNextChar
FBReadCheckForRoom:
 LD A,C
 LD (NoDirEntries),A
 PUSH HL
 POP IX
 EX DE,HL
 LD HL,VarsLastAddr
 SBC HL,DE
 LD DE,270
 SBC HL,DE
 JR C,FBListEntries
 POP AF
 JR FBReadNextEntry
FBReadFileEntry:
 INC HL
FBReadFileEntryNextChar:
 LD A,(HL)
 INC HL
 AND A
 JR NZ,FBReadFileEntryNextChar
 LD DE,5
 SBC HL,DE
 LD DE,StrAsm
 CALL StrCmp
 JR Z,FBReadCheckForRoom
 POP AF
 JR FBReadNextEntry
FBListEntries:
 CALL ClearEditArea
 LD A,(FirstLineOfScreen)
 LD B,A
 LD C,0
 LD HL,StrFileIndent
 CALL PrintStr
 LD HL,StrSelectFile
 LD A,(ModeFlag)
 BIT 7,A
 JR Z,FBPrintFirstLine
 LD HL,StrSaveToCurrent
FBPrintFirstLine:
 LD A,(SelectedEntry)
 CP 254
 CALL PrintListItem
 INC B
 LD C,0
 LD HL,StrDir
 CALL PrintStr
 LD HL,StrDotDot
 LD A,(SelectedEntry)
 CP 255
 CALL PrintListItem
 LD IX,VarsStartAddr
 LD E,0
FBPrintNextEntry:
 LD A,(NoDirEntries)
 CP E
 JR Z,FBWaitForKeypress
 INC B
 LD C,0
 LD HL,StrDir
 BIT 4,(IX+0)
 JR NZ,FBPrintEntryName
 LD HL,StrFileIndent
FBPrintEntryName:
 PUSH DE
 CALL PrintStr
 POP DE
 PUSH IX
 POP HL
 INC HL
 LD A,(SelectedEntry)
 CP E
 PUSH DE
 CALL PrintListItem
 POP DE
 INC E
 DEC HL
FBListingFindNext:
 LD A,(HL)
 INC HL
 AND A
 JR NZ,FBListingFindNext
 PUSH HL
 POP IX
 JR FBPrintNextEntry
FBWaitForKeypress:
 CALL InputChar
 CP 8
 JR NZ,FBWFKNotLeft
 POP AF
 PUSH AF
 RST 8
 DEFB 0xA7
 POP AF
 JP FBReadPageOfEntries
FBWFKNotLeft:
 CP 9
 JR NZ,FBWFKNotRight
 LD A,(NoDirEntries)
 AND A
 JR Z,FBWaitForKeypress
 POP AF
 JP FBReadPageOfEntries
FBWFKNotRight:
 CP 10
 JR NZ,FBWFKNotDown
 LD A,(NoDirEntries)
 LD E,A
 LD A,(SelectedEntry)
 INC A
 CP E
 JR Z,FBWaitForKeypress
 LD (SelectedEntry),A
 JP FBListEntries
FBWFKNotDown:
 CP 11
 JR NZ,FBWFKNotUp
 LD A,(SelectedEntry)
 CP 254
 JR Z,FBWaitForKeypress
 JR C,FBWFKGoUp
 LD A,(ModeFlag)
 BIT 7,A
 JR Z,FBWaitForKeypress
FBWFKGoUp:
 LD A,(SelectedEntry)
 DEC A
 LD (SelectedEntry),A
 JP FBListEntries
FBWFKNotUp:
 CP 3
 JR NZ,FBWFKNotBreak
 LD IX,0
 POP AF
 RST 8
 DEFB 0x9B
 RET
FBWFKNotBreak:
 CP 13
 JR NZ,FBWaitForKeypress
 POP AF
 RST 8
 DEFB 0x9B
 RET C
 LD A,(SelectedEntry)
 CP 254
 RET Z
 LD IX,StrDotDot
 JR NC,FBChangeDir
 LD E,0
 LD IX,VarsStartAddr
FBFindSelected:
 INC IX
 LD A,(SelectedEntry)
 CP E
 JR Z,FBSelectedFound
FBFindSelectedNextChar:
 LD A,(IX+0)
 INC IX
 AND A
 JR NZ,FBFindSelectedNextChar
 INC E
 JR FBFindSelected
FBSelectedFound:
 BIT 4,(IX-1)
 RET Z
FBChangeDir:
 LD A,'$'
 RST 8
 DEFB 0xA9
 JP FileBrowse
 
 
; Print String in HL at B,C
; If zero print inverted
PrintListItem:
 JP NZ,PrintStr
 JP PrintStrInv


; Compare 0 - terminated string in (HL+1) to code in (DE)
; Return zero if match, only A register affected
FSStrCmp:
 PUSH HL
 PUSH DE
 DEC DE
FSSCNNext:
 INC HL
 INC DE
 LD A,(HL)
 AND A
 JR Z,FSSCExit
 LD A,(DE)
 CP (HL)
 JR Z,FSSCNNext
FSSCExit:
 POP DE
 POP HL
 RET

; Search for string in string buffer from cursor and forward
; If found, set new screen position to line with string
; and new cursor position to char after string
; and update edit area of screen
FindString:
 CALL SetCursorBankAsActive
 LD HL,(pSourceCursor)
 EX DE,HL
 LD HL,SearchString
FSNext:
 LD A,(DE)
 AND A
 JR Z,FSNextBank
 INC DE
 CP (HL)
 JR NZ,FSNext
 CALL FSStrCmp
 JR NZ,FSNext
 DEC DE
 LD A,(SourceBankActive)
 LD (SourceBankCursor),A
 LD (SourceBankScreen),A
 LD C,0
FSFindSOL:
 LD A,(DE)
 CP 13
 JR Z,FSFoundSOL
 INC C
 DEC DE
 LD A,D
 CP SourceStartHigh
 JR NC,FSFindSOL
FSFoundSOL:
 DEC C
 INC DE
 EX DE,HL
 LD (pSourceScreen),HL
FSFindCursorPos:
 INC C
 INC DE
 LD A,(DE)
 AND A
 JR NZ,FSFindCursorPos
 LD (CursorSourceY),A
 LD B,A
 LD A,C
 LD (CursorLastX),A
 ADD HL,BC
 LD (pSourceCursor),HL
 CALL ClearEditArea
 JP SourceScreenDump
FSNextBank:
 PUSH HL
 CALL SourceNextBankActive
 POP HL
 RET C
 LD DE,SourceStartAddr
 JR FSNext

DebugRow:
 DEFB 8
DebugColumn:
 DEFB 5
EntryAddress:
 DEFW 0
EntryFlag:
 DEFB 0
ExprSP:
 DEFW 0
ExprFlags:
 DEFB 0
ExprValue1:
 DEFW 0
ExprValue1High:
 DEFB 0
ExprValue1Sign:
 DEFB 0
ExprValue2:
 DEFW 0
ExprValue2High:
 DEFB 0
ExprValue2Sign:
 DEFB 0
ExprResult:
 DEFW 0
ExprResultHigh:
 DEFB 0
ExprResultSign:
 DEFB 0
ExprSpec:
 DEFB 0
ExprOp:
 DEFB 0
pExprStart:
 DEFW 0
pExprLast:
 DEFW 0
DecimalDigitsByte:
 DEFB 100,10,1
DecimalDigitsWord:
 DEFW 10000,1000,100
DecimalDigitsWord10:
 DEFW 10,1
DecimalSum:
 DEFW 0
ColorThemeNumber:
 DEFB 0
ColorThemes:
 DEFB %11111101,%00100110,%11111101,0
 DEFB %00000001,%10010010,%01000001,%10010010
FirstLineOfScreen:
 DEFB 0
LastLineOfScreen:
 DEFB 31
EditAreaLines:
 DEFB 30
NoDirEntries:
 DEFB 0
SelectedEntry:
 DEFB 0
KeypressSymbol:
 DEFB 0
KeypressShift:
 DEFB 0
LastKeySymbol:
 DEFB 0
LastKeyShift:
 DEFB 0
KeypressMode:
 DEFB 0
KeyInputDefOld:
 DEFB 0xFE,CapsShift,'z','x','c','v'
 DEFB 0xFD,'a','s','d','f','g'
 DEFB 0xFB,'q','w','e','r','t'
 DEFB 0xF7,'1','2','3','4','5'
 DEFB 0xEF,'0','9','8','7','6'
 DEFB 0xDF,'p','o','i','u','y'
 DEFB 0xBF,13,'l','k','j','h'
 DEFB 0x7F,32,SymbolShift,'m','n','b'
KeyInputDefExt:
 DEFB 9,8,10,11,46,44,34,59
 DEFB 14,6,15,4,5,3,7,12
CapsShiftNumbers:
 DEFB 12,7,6,4,20,8,10,11,9,21
SymbolShiftNumbers:
 DEFB '_','!','@','#','$','%','&',39,'(',')'
SymbolShiftLetters:
 DEFB '~','*','?',92,25,'{','}',94,28,'-','+'
 DEFB '=',46,44,59,34,24,'<',124,'>',']','/',127,96,'[',':'
pCommandFilename:
 DEFW 0
SourceFilename:
 DEFB 0
 DEFS 14
ObjectFilename:
 DEFB 0
 DEFS 14
pParserCurrentLine:
 DEFW SourceStartAddr
pParserNextSymbol:
 DEFW SourceStartAddr
SourceBankActive:
 DEFB 0
SourceBankCursor:
 DEFB 0
SourceBankScreen:
 DEFB 0
SourceLastBank:
 DEFB 0
VarsBank:
 DEFB 0
pObjectNextCode:
 DEFW ObjectStartAddr
ObjectBank:
 DEFB 0
pObjectORGHeader:
 DEFW 0
ObjectORGHeaderBank:
 DEFB 0
ObjectPC:
 DEFW 0
NoORG:
 DEFB 0
pNextVar:
 DEFW 0
pSourceVar:
 DEFW 0
pSourceScreen:
 DEFW SourceStartAddr
pSourceCursor:
 DEFW SourceStartAddr
pMemCopyStart:
 DEFW 0
MemCopySize:
 DEFW 0
ModeFlag:
 DEFB 0
CursorX:
 DEFB 0
CursorLastX:
 DEFB 0
CursorSourceY:
 DEFB 0
NoCharsInLine:
 DEFB 0
LineBuffer:
 DEFS 80
SearchString:
 DEFS 80
SourceOpcode:
 DEFS 8
SourceArgSpecs:
 DEFS 8
NoValueArgs:
 DEFB 0
NextValueArg:
 DEFB 0
ValueSpec1:
 DEFB 0
ValueSpec2:
 DEFB 0
ValueArg1:
 DEFW 0
ValueArg2:
 DEFW 0
pArgSpecsExpected:
 DEFW 0
; Z80 instructions
OpZ80:
 DEFB "LD",0,0
 DEFW ArgsLD
 DEFB 42
 DEFB "PUSH"
 DEFW ArgsPUSH
 DEFB 7
 DEFB "POP",0
 DEFW ArgsPOP
 DEFB 6
 DEFB "JP",0,0
 DEFW ArgsJP
 DEFB 13
 DEFB "JR",0,0
 DEFW ArgsJR
 DEFB 5
 DEFB "CALL"
 DEFW ArgsCALL
 DEFB 9
 DEFB "EX",0,0
 DEFW ArgsEX
 DEFB 5
 DEFB "INC",0
 DEFW ArgsINC
 DEFB 10
 DEFB "DEC",0
 DEFW ArgsDEC
 DEFB 10
 DEFB "ADD",0
 DEFW ArgsADD
 DEFB 23
 DEFB "ADC",0
 DEFW ArgsADC
 DEFB 9
 DEFB "SUB",0
 DEFW ArgsSUB
 DEFB 5
 DEFB "SBC",0
 DEFW ArgsSBC
 DEFB 9
 DEFB "AND",0
 DEFW ArgsAND
 DEFB 5
 DEFB "OR",0,0
 DEFW ArgsOR
 DEFB 5
 DEFB "XOR",0
 DEFW ArgsXOR
 DEFB 5
 DEFB "CP",0,0
 DEFW ArgsCP
 DEFB 5
 DEFB "EXX",0
 DEFW ArgsEXX
 DEFB 1
 DEFB "LDI",0
 DEFW ArgsLDI
 DEFB 1
 DEFB "LDIR"
 DEFW ArgsLDIR
 DEFB 1
 DEFB "LDD",0
 DEFW ArgsLDD
 DEFB 1
 DEFB "LDDR"
 DEFW ArgsLDDR
 DEFB 1
 DEFB "CPI",0
 DEFW ArgsCPI
 DEFB 1
 DEFB "CPIR"
 DEFW ArgsCPIR
 DEFB 1
 DEFB "CPD",0
 DEFW ArgsCPD
 DEFB 1
 DEFB "CPDR"
 DEFW ArgsCPDR
 DEFB 1
 DEFB "DAA",0
 DEFW ArgsDAA
 DEFB 1
 DEFB "CPL",0
 DEFW ArgsCPL
 DEFB 1
 DEFB "NEG",0
 DEFW ArgsNEG
 DEFB 1
 DEFB "CCF",0
 DEFW ArgsCCF
 DEFB 1
 DEFB "SCF",0
 DEFW ArgsSCF
 DEFB 1
 DEFB "NOP",0
 DEFW ArgsNOP
 DEFB 1
 DEFB "HALT"
 DEFW ArgsHALT
 DEFB 1
 DEFB "DI",0,0
 DEFW ArgsDI
 DEFB 1
 DEFB "EI",0,0
 DEFW ArgsEI
 DEFB 1
 DEFB "IM",0,0
 DEFW ArgsIM
 DEFB 3
 DEFB "RLCA"
 DEFW ArgsRLCA
 DEFB 1
 DEFB "RLA",0
 DEFW ArgsRLA
 DEFB 1
 DEFB "RRCA"
 DEFW ArgsRRCA
 DEFB 1
 DEFB "RRA",0
 DEFW ArgsRRA
 DEFB 1
 DEFB "RLC",0
 DEFW ArgsRLC
 DEFB 4
 DEFB "RL",0,0
 DEFW ArgsRL
 DEFB 4
 DEFB "RRC",0
 DEFW ArgsRRC
 DEFB 4
 DEFB "RR",0,0
 DEFW ArgsRR
 DEFB 4
 DEFB "SLA",0
 DEFW ArgsSLA
 DEFB 4
 DEFB "SRA",0
 DEFW ArgsSRA
 DEFB 4
 DEFB "SRL",0
 DEFW ArgsSRL
 DEFB 4
 DEFB "RLD",0
 DEFW ArgsRLD
 DEFB 1
 DEFB "RRD",0
 DEFW ArgsRRD
 DEFB 1
 DEFB "BIT",0
 DEFW ArgsBIT
 DEFB 4
 DEFB "SET",0
 DEFW ArgsSET
 DEFB 4
 DEFB "RES",0
 DEFW ArgsRES
 DEFB 4
 DEFB "DJNZ"
 DEFW ArgsDJNZ
 DEFB 1
 DEFB "RET",0
 DEFW ArgsRET
 DEFB 9
 DEFB "RETI"
 DEFW ArgsRETI
 DEFB 1
 DEFB "RETN"
 DEFW ArgsRETN
 DEFB 1
 DEFB "RST",0
 DEFW ArgsRST
 DEFB 1
 DEFB "IN",0,0
 DEFW ArgsIN
 DEFB 2
 DEFB "INI",0
 DEFW ArgsINI
 DEFB 1
 DEFB "INIR"
 DEFW ArgsINIR
 DEFB 1
 DEFB "IND",0
 DEFW ArgsIND
 DEFB 1
 DEFB "INDR"
 DEFW ArgsINDR
 DEFB 1
 DEFB "OUT",0
 DEFW ArgsOUT
 DEFB 2
 DEFB "OUTI"
 DEFW ArgsOUTI
 DEFB 1
 DEFB "OTIR"
 DEFW ArgsOTIR
 DEFB 1
 DEFB "OUTD"
 DEFW ArgsOUTD
 DEFB 1
 DEFB "OTDR"
 DEFW ArgsOTDR
 DEFB 1
; Z80N instructions, 4 letter
OpZ80N4:
 DEFB "LDIX"
 DEFW ArgsLDIX
 DEFB 1
 DEFB "LDWS"
 DEFW ArgsLDWS
 DEFB 1
 DEFB "LIRX"
 DEFW ArgsLDIRX
 DEFB 1
 DEFB "LDDX"
 DEFW ArgsLDDX
 DEFB 1
 DEFB "LDRX"
 DEFW ArgsLDDRX
 DEFB 1
 DEFB "LPRX"
 DEFW ArgsLDPIRX
 DEFB 1
 DEFB "OTIB"
 DEFW ArgsOUTINB
 DEFB 1
 DEFB "MUL",0
 DEFW ArgsMUL
 DEFB 1
 DEFB "SWAP"
 DEFW ArgsSWAPNIB
 DEFB 1
 DEFB "MIRR"
 DEFW ArgsMIRROR
 DEFB 1
 DEFB "NREG"
 DEFW ArgsNEXTREG
 DEFB 2
 DEFB "PXDN"
 DEFW ArgsPIXELDN
 DEFB 1
 DEFB "PXAD"
 DEFW ArgsPIXELAD
 DEFB 1
 DEFB "STAE"
 DEFW ArgsSETAE
 DEFB 1
 DEFB "TEST"
 DEFW ArgsTEST
 DEFB 1
 DEFB "BSLA"
 DEFW ArgsBSLA
 DEFB 1
 DEFB "BSRA"
 DEFW ArgsBSRA
 DEFB 1
 DEFB "BSRL"
 DEFW ArgsBSRL
 DEFB 1
 DEFB "BSRF"
 DEFW ArgsBSRF
 DEFB 1
 DEFB "BRLC"
 DEFW ArgsBRLC
 DEFB 1
; Z80N instructions, 7 letter
OpZ80N7:
 DEFB "LDIRX",0,0
 DEFW ArgsLDIRX
 DEFB 1
 DEFB "LDDRX",0,0
 DEFW ArgsLDDRX
 DEFB 1
 DEFB "LDPIRX",0
 DEFW ArgsLDPIRX
 DEFB 1
 DEFB "OUTINB",0
 DEFW ArgsOUTINB
 DEFB 1
 DEFB "SWAPNIB"
 DEFW ArgsSWAPNIB
 DEFB 1
 DEFB "MIRROR",0
 DEFW ArgsMIRROR
 DEFB 1
 DEFB "NEXTREG"
 DEFW ArgsNEXTREG
 DEFB 2
 DEFB "PIXELDN"
 DEFW ArgsPIXELDN
 DEFB 1
 DEFB "PIXELAD"
 DEFW ArgsPIXELAD
 DEFB 1
 DEFB "SETAE",0,0
 DEFW ArgsSETAE
 DEFB 1
Reg8Names:
 DEFB 'B','C','D','E','H','L','F','A'
ArgStrings:
 DEFB ',',0,0
 DEFB '(',0,0
 DEFB ')',0,0
 DEFB '+',0,0
 DEFB "NC",0
 DEFB 'Z',0,0
 DEFB "NZ",0
 DEFB "PO",0
 DEFB "PE",0
 DEFB 'P',0,0
 DEFB 'M',0,0
 DEFB "AF",0x27
 DEFB "AF",0
 DEFB "BC",0
 DEFB "DE",0
 DEFB "HL",0
 DEFB "IX",0
 DEFB "IY",0
 DEFB "SP",0
 DEFB 'I',0,0
 DEFB 'R',0,0
 DEFB '-',0,0
CommandPointers:
 DEFW StrMemory,StrFind,StrAssemble,StrAssembleShort
 DEFW StrSave,StrLoad,StrSaveas,StrNew,StrExit
StatementPointers:
 DEFW StrOrg,StrDefb,StrDefw,StrDefs
ErrorStringPointers:
 DEFW StrErr1,StrErr2,StrErr3,StrErr4,StrErr5
 DEFW StrErr6,StrErr7,StrErr8,StrErr9,StrErr10
 DEFW StrErr11,StrErr12,StrErr13,StrErr14,StrErr15
 DEFW StrErr16,StrErr17,StrErr18,StrErr19,StrErr20
 DEFW StrErr21,StrErr22,StrErr23,StrErr24,StrErr25
StrMemory:
 DEFB "MEMORY",0
StrUsed:
 DEFB "Used(reserved): ",0
StrFree:
 DEFB "Free: ",0
StrKb:
 DEFB "kb",0
StrAssemble:
 DEFB "ASSEMBLE",0
StrAssembleShort:
 DEFB "A",0
StrNonext:
 DEFB "-nonext",0
StrAssembling:
 DEFB "Assembling...",0
StrAssReport:
 DEFB "Object code size: ",0
StrFind:
 DEFB "FIND",0
StrExit:
 DEFB "EXIT",0
StrNew:
 DEFB "NEW",0
StrSave:
 DEFB "SAVE",0
StrSaveas:
 DEFB "SAVEAS",0
StrLoad:
 DEFB "LOAD",0
StrAsm:
 DEFB ".asm",0
StrTap:
 DEFB ".tap",0
StrSep:
 DEFB " - ",0
StrSaving:
 DEFB "Saving...",0
StrOk:
 DEFB "Ok",0
StrLoading:
 DEFB "Loading...",0
StrSaveToCurrent:
 DEFB "Save to current directory",0
StrSelectFile:
 DEFB "Select file to load",0
StrDir:
 DEFB "DIR  ",0
StrFileIndent:
 DEFB "     ",0
StrDotDot:
 DEFB "..",0
StrDefine:
 DEFB "DEFINE",0
StrOrg:
 DEFB "ORG",0
StrDefb:
 DEFB "DEFB",0
StrDefw:
 DEFB "DEFW",0
StrDefs:
 DEFB "DEFS",0
StrSet:
 DEFB "SET",0
StrEntry:
 DEFB "ENTRY",0
StrEqu:
 DEFB "EQU",0
StrErr1:
 DEFB "Invalid command",0
StrErr2:
 DEFB "Missing file name",0
StrErr3:
 DEFB "Invalid file name",0
StrErr4:
 DEFB "Invalid address",0
StrErr5:
 DEFB "Error selecting file or directory",0
StrErr6:
 DEFB "Multiple definitions of variable",0
StrErr7:
 DEFB "Variable not found",0
StrErr8:
 DEFB "Syntax error",0
StrErr9:
 DEFB "Argument mismatch",0
StrErr10:
 DEFB "Out of memory",0
StrErr11:
 DEFB "Invalid number",0
StrErr12:
 DEFB "Too many code blocks",0
StrErr13:
 DEFB "Relative addressing out of range",0
StrErr14:
 DEFB "Load error",0
StrErr15:
 DEFB "Save error",0
StrErr16:
 DEFB "ORG expected",0
StrErr17:
 DEFB "Byte expected",0
StrErr18:
 DEFB "Invalid argument",0
StrErr19:
 DEFB "Overflow in expression",0
StrErr20:
 DEFB "Invalid operation",0
StrErr21:
 DEFB "Division by 0",0
StrErr22:
 DEFB "Invalid assignment",0
StrErr23:
 DEFB "Debug exit point",0
StrErr24:
 DEFB "Invalid ENTRY value",0
StrErr25:
 DEFB "Word Expected",0
; Table of instruction argument specs
ArgsLD:
 DEFB 248,1,248,0,0,0,0,0x2F,0x40,0,0,0
 DEFB 248,1,255,0,0,0,0,0x27,0x06,0,0,0
 DEFB 248,1,2,16,3,0,0,0x23,0x46,0,0,0
 DEFB 248,1,2,17,4,253,3,0xE7,0xDD,0x46,0,0
 DEFB 248,1,2,18,4,253,3,0xE7,0xFD,0x46,0,0
 DEFB 2,16,3,1,248,0,0,0x03,0x70,0,0,0
 DEFB 2,17,4,253,3,1,248,0xCD,0xDD,0x70,0,0
 DEFB 2,18,4,253,3,1,248,0xCD,0xFD,0x70,0,0
 DEFB 2,16,3,1,255,0,0,0x01,0x36,0,0,0
 DEFB 2,17,4,253,3,1,255,0x85,0xDD,0x36,0,0
 DEFB 2,18,4,253,3,1,255,0x85,0xFD,0x36,0,0
 DEFB 71,1,2,14,3,0,0,0,0x0A,0,0,0
 DEFB 71,1,2,15,3,0,0,0,0x1A,0,0,0
 DEFB 71,1,2,252,3,0,0,0x02,0x3A,0,0,0
 DEFB 2,14,3,1,71,0,0,0,0x02,0,0,0
 DEFB 2,15,3,1,71,0,0,0,0x12,0,0,0
 DEFB 2,252,3,1,71,0,0,0x02,0x32,0,0,0
 DEFB 71,1,20,0,0,0,0,0x80,0xED,0x57,0,0
 DEFB 71,1,21,0,0,0,0,0x80,0xED,0x5F,0,0
 DEFB 20,1,71,0,0,0,0,0x80,0xED,0x47,0,0
 DEFB 21,1,71,0,0,0,0,0x80,0xED,0x4F,0,0
 DEFB 14,1,251,0,0,0,0,0x02,0x01,0,0,0
 DEFB 15,1,251,0,0,0,0,0x02,0x11,0,0,0
 DEFB 16,1,251,0,0,0,0,0x02,0x21,0,0,0
 DEFB 19,1,251,0,0,0,0,0x02,0x31,0,0,0
 DEFB 17,1,251,0,0,0,0,0x82,0xDD,0x21,0,0
 DEFB 18,1,251,0,0,0,0,0x82,0xFD,0x21,0,0
 DEFB 16,1,2,252,3,0,0,0x02,0x2A,0,0,0
 DEFB 14,1,2,252,3,0,0,0x82,0xED,0x4B,0,0
 DEFB 15,1,2,252,3,0,0,0x82,0xED,0x5B,0,0
 DEFB 19,1,2,252,3,0,0,0x82,0xED,0x7B,0,0
 DEFB 17,1,2,252,3,0,0,0x82,0xDD,0x2A,0,0
 DEFB 18,1,2,252,3,0,0,0x82,0xFD,0x2A,0,0
 DEFB 2,252,3,1,16,0,0,0x02,0x22,0,0,0
 DEFB 2,252,3,1,14,0,0,0x82,0xED,0x43,0,0
 DEFB 2,252,3,1,15,0,0,0x82,0xED,0x53,0,0
 DEFB 2,252,3,1,19,0,0,0x82,0xED,0x73,0,0
 DEFB 2,252,3,1,17,0,0,0x82,0xDD,0x22,0,0
 DEFB 2,252,3,1,18,0,0,0x82,0xFD,0x22,0,0
 DEFB 19,1,16,0,0,0,0,0,0xF9,0,0,0
 DEFB 19,1,17,0,0,0,0,0x80,0xDD,0xF9,0,0
 DEFB 19,1,18,0,0,0,0,0x80,0xFD,0xF9,0,0
ArgsPUSH:
 DEFB 14,0,0,0,0,0,0,0,0xC5,0,0,0
 DEFB 15,0,0,0,0,0,0,0,0xD5,0,0,0
 DEFB 16,0,0,0,0,0,0,0,0xE5,0,0,0
 DEFB 13,0,0,0,0,0,0,0,0xF5,0,0,0
 DEFB 17,0,0,0,0,0,0,0x80,0xDD,0xE5,0,0
 DEFB 18,0,0,0,0,0,0,0x80,0xFD,0xE5,0,0
 DEFB 251,0,0,0,0,0,0,0x92,0xED,0x8A,0,0
ArgsPOP:
 DEFB 14,0,0,0,0,0,0,0,0xC1,0,0,0
 DEFB 15,0,0,0,0,0,0,0,0xD1,0,0,0
 DEFB 16,0,0,0,0,0,0,0,0xE1,0,0,0
 DEFB 13,0,0,0,0,0,0,0,0xF1,0,0,0
 DEFB 17,0,0,0,0,0,0,0x80,0xDD,0xE1,0,0
 DEFB 18,0,0,0,0,0,0,0x80,0xFD,0xE1,0,0
ArgsEX:
 DEFB 15,1,16,0,0,0,0,0,0xEB,0,0,0
 DEFB 13,1,12,0,0,0,0,0,0x08,0,0,0
 DEFB 2,19,3,1,16,0,0,0,0xE3,0,0,0
 DEFB 2,19,3,1,17,0,0,0x80,0xDD,0xE3,0,0
 DEFB 2,19,3,1,18,0,0,0x80,0xFD,0xE3,0,0
ArgsEXX:
 DEFB 0,0,0,0,0,0,0,0,0xD9,0,0,0
ArgsLDI:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xA0,0,0
ArgsLDIR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xB0,0,0
ArgsLDD:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xA8,0,0
ArgsLDDR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xB8,0,0
ArgsCPI:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xA1,0,0
ArgsCPIR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xB1,0,0
ArgsCPD:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xA9,0,0
ArgsCPDR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xB9,0,0
ArgsADD:
 DEFB 71,1,248,0,0,0,0,0x03,0x80,0,0,0
 DEFB 71,1,255,0,0,0,0,0x01,0xC6,0,0,0
 DEFB 71,1,2,16,3,0,0,0,0x86,0,0,0
 DEFB 71,1,2,17,4,253,3,0x81,0xDD,0x86,0,0
 DEFB 71,1,2,18,4,253,3,0x81,0xFD,0x86,0,0
 DEFB 16,1,14,0,0,0,0,0,0x09,0,0,0
 DEFB 16,1,15,0,0,0,0,0,0x19,0,0,0
 DEFB 16,1,16,0,0,0,0,0,0x29,0,0,0
 DEFB 16,1,19,0,0,0,0,0,0x39,0,0,0
 DEFB 17,1,14,0,0,0,0,0x80,0xDD,0x09,0,0
 DEFB 17,1,15,0,0,0,0,0x80,0xDD,0x19,0,0
 DEFB 17,1,17,0,0,0,0,0x80,0xDD,0x29,0,0
 DEFB 17,1,19,0,0,0,0,0x80,0xDD,0x39,0,0
 DEFB 18,1,14,0,0,0,0,0x80,0xFD,0x09,0,0
 DEFB 18,1,15,0,0,0,0,0x80,0xFD,0x19,0,0
 DEFB 18,1,18,0,0,0,0,0x80,0xFD,0x29,0,0
 DEFB 18,1,19,0,0,0,0,0x80,0xFD,0x39,0,0
 DEFB 16,1,71,0,0,0,0,0x90,0xED,0x31,0,0
 DEFB 15,1,71,0,0,0,0,0x90,0xED,0x32,0,0
 DEFB 14,1,71,0,0,0,0,0x90,0xED,0x33,0,0
 DEFB 16,1,251,0,0,0,0,0x92,0xED,0x34,0,0
 DEFB 15,1,251,0,0,0,0,0x92,0xED,0x35,0,0
 DEFB 14,1,251,0,0,0,0,0x92,0xED,0x36,0,0
ArgsADC:
 DEFB 71,1,248,0,0,0,0,0x03,0x88,0,0,0
 DEFB 71,1,255,0,0,0,0,0x01,0xCE,0,0,0
 DEFB 71,1,2,16,3,0,0,0,0x8E,0,0,0
 DEFB 71,1,2,17,4,253,3,0x81,0xDD,0x8E,0,0
 DEFB 71,1,2,18,4,253,3,0x81,0xFD,0x8E,0,0
 DEFB 16,1,14,0,0,0,0,0x80,0xED,0x4A,0,0
 DEFB 16,1,15,0,0,0,0,0x80,0xED,0x5A,0,0
 DEFB 16,1,16,0,0,0,0,0x80,0xED,0x6A,0,0
 DEFB 16,1,19,0,0,0,0,0x80,0xED,0x7A,0,0
ArgsSUB:
 DEFB 248,0,0,0,0,0,0,0x03,0x90,0,0,0
 DEFB 255,0,0,0,0,0,0,0x01,0xD6,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0x96,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0x96,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0x96,0,0
ArgsSBC:
 DEFB 71,1,248,0,0,0,0,0x03,0x98,0,0,0
 DEFB 71,1,255,0,0,0,0,0x01,0xDE,0,0,0
 DEFB 71,1,2,16,3,0,0,0,0x9E,0,0,0
 DEFB 71,1,2,17,4,253,3,0x81,0xDD,0x9E,0,0
 DEFB 71,1,2,18,4,253,3,0x81,0xFD,0x9E,0,0
 DEFB 16,1,14,0,0,0,0,0x80,0xED,0x42,0,0
 DEFB 16,1,15,0,0,0,0,0x80,0xED,0x52,0,0
 DEFB 16,1,16,0,0,0,0,0x80,0xED,0x62,0,0
 DEFB 16,1,19,0,0,0,0,0x80,0xED,0x72,0,0
ArgsAND:
 DEFB 248,0,0,0,0,0,0,0x03,0xA0,0,0,0
 DEFB 254,0,0,0,0,0,0,0x01,0xE6,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0xA6,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xA6,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xA6,0,0
ArgsOR:
 DEFB 248,0,0,0,0,0,0,0x03,0xB0,0,0,0
 DEFB 254,0,0,0,0,0,0,0x01,0xF6,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0xB6,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xB6,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xB6,0,0
ArgsXOR:
 DEFB 248,0,0,0,0,0,0,0x03,0xA8,0,0,0
 DEFB 254,0,0,0,0,0,0,0x01,0xEE,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0xAE,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xAE,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xAE,0,0
ArgsCP:
 DEFB 248,0,0,0,0,0,0,0x03,0xB8,0,0,0
 DEFB 254,0,0,0,0,0,0,0x01,0xFE,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0xBE,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xBE,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xBE,0,0
ArgsINC:
 DEFB 248,0,0,0,0,0,0,0x23,0x04,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0x34,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0x34,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0x34,0,0
 DEFB 14,0,0,0,0,0,0,0,0x03,0,0,0
 DEFB 15,0,0,0,0,0,0,0,0x13,0,0,0
 DEFB 16,0,0,0,0,0,0,0,0x23,0,0,0
 DEFB 19,0,0,0,0,0,0,0,0x33,0,0,0
 DEFB 17,0,0,0,0,0,0,0x80,0xDD,0x23,0,0
 DEFB 18,0,0,0,0,0,0,0x80,0xFD,0x23,0,0
ArgsDEC:
 DEFB 248,0,0,0,0,0,0,0x23,0x05,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0x35,0,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0x35,0,0
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0x35,0,0
 DEFB 14,0,0,0,0,0,0,0,0x0B,0,0,0
 DEFB 15,0,0,0,0,0,0,0,0x1B,0,0,0
 DEFB 16,0,0,0,0,0,0,0,0x2B,0,0,0
 DEFB 19,0,0,0,0,0,0,0,0x3B,0,0,0
 DEFB 17,0,0,0,0,0,0,0x80,0xDD,0x2B,0,0
 DEFB 18,0,0,0,0,0,0,0x80,0xFD,0x2B,0,0
ArgsDAA:
 DEFB 0,0,0,0,0,0,0,0,0x27,0,0,0
ArgsCPL:
 DEFB 0,0,0,0,0,0,0,0,0x2F,0,0,0
ArgsNEG:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0x44,0,0
ArgsCCF:
 DEFB 0,0,0,0,0,0,0,0,0x3F,0,0,0
ArgsSCF:
 DEFB 0,0,0,0,0,0,0,0,0x37,0,0,0
ArgsNOP:
 DEFB 0,0,0,0,0,0,0,0,0,0,0,0
ArgsHALT:
 DEFB 0,0,0,0,0,0,0,0,0x76,0,0,0
ArgsDI:
 DEFB 0,0,0,0,0,0,0,0,0xF3,0,0,0
ArgsEI:
 DEFB 0,0,0,0,0,0,0,0,0xFB,0,0,0
ArgsIM:
 DEFB 32,0,0,0,0,0,0,0x80,0xED,0x46,0,0
 DEFB 33,0,0,0,0,0,0,0x80,0xED,0x56,0,0
 DEFB 34,0,0,0,0,0,0,0x80,0xED,0x5E,0,0
ArgsRLCA:
 DEFB 0,0,0,0,0,0,0,0,0x07,0,0,0
ArgsRLA:
 DEFB 0,0,0,0,0,0,0,0,0x17,0,0,0
ArgsRRCA:
 DEFB 0,0,0,0,0,0,0,0,0x0F,0,0,0
ArgsRRA:
 DEFB 0,0,0,0,0,0,0,0,0x1F,0,0,0
ArgsRLC:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x06,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x06
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x06
ArgsRL:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0x10,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x16,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x16
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x16
ArgsRRC:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0x08,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x0E,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x0E
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x0E
ArgsRR:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0x18,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x1E,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x1E
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x1E
ArgsSLA:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0x20,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x26,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x26
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x26
ArgsSRA:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0x28,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x2E,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x2E
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x2E
ArgsSRL:
 DEFB 248,0,0,0,0,0,0,0xC3,0xCB,0x38,0,0
 DEFB 2,16,3,0,0,0,0,0x80,0xCB,0x3E,0,0
 DEFB 2,17,4,253,3,0,0,0x81,0xDD,0xCB,0,0x3E
 DEFB 2,18,4,253,3,0,0,0x81,0xFD,0xCB,0,0x3E
ArgsRLD:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0x6F,0,0
ArgsRRD:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0x67,0,0
ArgsBIT:
 DEFB 247,1,248,0,0,0,0,0xEF,0xCB,0x40,0,0
 DEFB 247,1,2,16,3,0,0,0xE3,0xCB,0x46,0,0
 DEFB 247,1,2,17,4,253,3,0xE3,0xDD,0xCB,0,0x46
 DEFB 247,1,2,18,4,253,3,0xE3,0xFD,0xCB,0,0x46
ArgsSET:
 DEFB 247,1,248,0,0,0,0,0xEF,0xCB,0xC0,0,0
 DEFB 247,1,2,16,3,0,0,0xE3,0xCB,0xC6,0,0
 DEFB 247,1,2,17,4,253,3,0xE3,0xDD,0xCB,0,0xC6
 DEFB 247,1,2,18,4,253,3,0xE3,0xFD,0xCB,0,0xC6
ArgsRES:
 DEFB 247,1,248,0,0,0,0,0xEF,0xCB,0x80,0,0
 DEFB 247,1,2,16,3,0,0,0xE3,0xCB,0x86,0,0
 DEFB 247,1,2,17,4,253,3,0xE3,0xDD,0xCB,0,0x86
 DEFB 247,1,2,18,4,253,3,0xE3,0xFD,0xCB,0,0x86
ArgsJP:
 DEFB 252,0,0,0,0,0,0,0x02,0xC3,0,0,0
 DEFB 7,1,252,0,0,0,0,0x02,0xC2,0,0,0
 DEFB 6,1,252,0,0,0,0,0x02,0xCA,0,0,0
 DEFB 5,1,252,0,0,0,0,0x02,0xD2,0,0,0
 DEFB 65,1,252,0,0,0,0,0x02,0xDA,0,0,0
 DEFB 8,1,252,0,0,0,0,0x02,0xE2,0,0,0
 DEFB 9,1,252,0,0,0,0,0x02,0xEA,0,0,0
 DEFB 10,1,252,0,0,0,0,0x02,0xF2,0,0,0
 DEFB 11,1,252,0,0,0,0,0x02,0xFA,0,0,0
 DEFB 2,16,3,0,0,0,0,0,0xE9,0,0,0
 DEFB 2,17,3,0,0,0,0,0x80,0xDD,0xE9,0,0
 DEFB 2,18,3,0,0,0,0,0x80,0xFD,0xE9,0,0
 DEFB 2,65,3,0,0,0,0,0x90,0xED,0x98,0,0
ArgsJR:
 DEFB 250,0,0,0,0,0,0,0x01,0x18,0,0,0
 DEFB 65,1,250,0,0,0,0,0x01,0x38,0,0,0
 DEFB 5,1,250,0,0,0,0,0x01,0x30,0,0,0
 DEFB 6,1,250,0,0,0,0,0x01,0x28,0,0,0
 DEFB 7,1,250,0,0,0,0,0x01,0x20,0,0,0
ArgsDJNZ:
 DEFB 250,0,0,0,0,0,0,0x01,0x10,0,0,0
ArgsCALL:
 DEFB 252,0,0,0,0,0,0,0x02,0xCD,0,0,0
 DEFB 7,1,252,0,0,0,0,0x02,0xC4,0,0,0
 DEFB 6,1,252,0,0,0,0,0x02,0xCC,0,0,0
 DEFB 5,1,252,0,0,0,0,0x02,0xD4,0,0,0
 DEFB 65,1,252,0,0,0,0,0x02,0xDC,0,0,0
 DEFB 8,1,252,0,0,0,0,0x02,0xE4,0,0,0
 DEFB 9,1,252,0,0,0,0,0x02,0xEC,0,0,0
 DEFB 10,1,252,0,0,0,0,0x02,0xF4,0,0,0
 DEFB 11,1,252,0,0,0,0,0x02,0xFC,0,0,0
ArgsRET:
 DEFB 0,0,0,0,0,0,0,0,0xC9,0,0,0
 DEFB 7,0,0,0,0,0,0,0,0xC0,0,0,0
 DEFB 6,0,0,0,0,0,0,0,0xC8,0,0,0
 DEFB 5,0,0,0,0,0,0,0,0xD0,0,0,0
 DEFB 65,0,0,0,0,0,0,0,0xD8,0,0,0
 DEFB 8,0,0,0,0,0,0,0,0xE0,0,0,0
 DEFB 9,0,0,0,0,0,0,0,0xE8,0,0,0
 DEFB 10,0,0,0,0,0,0,0,0xF0,0,0,0
 DEFB 11,0,0,0,0,0,0,0,0xF8,0,0,0
ArgsRETI:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0x4D,0,0
ArgsRETN:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0x45,0,0
ArgsRST:
 DEFB 246,0,0,0,0,0,0,0x23,0xC7,0,0,0
ArgsIN:
 DEFB 71,1,2,254,3,0,0,0x01,0xDB,0,0,0
 DEFB 248,1,2,65,3,0,0,0xA3,0xED,0x40,0,0
ArgsINI:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xA2,0,0
ArgsINIR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xB2,0,0
ArgsIND:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xAA,0,0
ArgsINDR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xBA,0,0
ArgsOUT:
 DEFB 2,254,3,1,71,0,0,0,0xD3,0,0,0
 DEFB 2,65,3,1,248,0,0,0xA3,0xED,0x41,0,0
ArgsOUTI:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xA3,0,0
ArgsOTIR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xB3,0,0
ArgsOUTD:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xAB,0,0
ArgsOTDR:
 DEFB 0,0,0,0,0,0,0,0x80,0xED,0xBB,0,0
ArgsLDIX:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0xA4,0,0
ArgsLDWS:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0xA5,0,0
ArgsLDIRX:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0xB4,0,0
ArgsLDDX:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0xAC,0,0
ArgsLDDRX:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0xBC,0,0
ArgsLDPIRX:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0xB7,0,0
ArgsOUTINB:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0x90,0,0
ArgsMUL:
 DEFB 66,1,67,0,0,0,0,0x90,0xED,0x30,0,0
ArgsSWAPNIB:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0x23,0,0
ArgsMIRROR:
 DEFB 71,0,0,0,0,0,0,0x90,0xED,0x24,0,0
ArgsNEXTREG:
 DEFB 254,1,255,0,0,0,0,0x95,0xED,0x91,0,0
 DEFB 254,1,71,0,0,0,0,0x91,0xED,0x92,0,0
ArgsPIXELDN:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0x93,0,0
ArgsPIXELAD:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0x94,0,0
ArgsSETAE:
 DEFB 0,0,0,0,0,0,0,0x90,0xED,0x95,0,0
ArgsTEST:
 DEFB 254,0,0,0,0,0,0,0x91,0xED,0x27,0,0
ArgsBSLA:
 DEFB 15,1,64,0,0,0,0,0x90,0xED,0x28,0,0
ArgsBSRA:
 DEFB 15,1,64,0,0,0,0,0x90,0xED,0x29,0,0
ArgsBSRL:
 DEFB 15,1,64,0,0,0,0,0x90,0xED,0x2A,0,0
ArgsBSRF:
 DEFB 15,1,64,0,0,0,0,0x90,0xED,0x2B,0,0
ArgsBRLC:
 DEFB 15,1,64,0,0,0,0,0x90,0xED,0x2C,0,0
TapFileHeaderBlock:
 DEFW 19
 DEFB 0
TapFileHeader:
 DEFB 0
TapFileFilename:
 DEFS 10
TapFileLength:
 DEFW 0
TapFileStart:
 DEFW 0
TapFileProgramLength:
 DEFW 0
TapFileHeaderChecksum:
 DEFB 0
TapFileProgramBlock:
 DEFW 78
 DEFB 255
TapFileBASIC:
 DEFB 0,10,13,0,0xFD,"24575",0x0E,0,0,0xFF,0x5F,0,0x0D
 DEFB 0,20,21,0,0xEB,"n=1",0x0E,0,0,1,0,0,0xCC
TapFileBlocksDigits:
 DEFB "001",0x0E,0,0
TapFileBlocksByte:
 DEFB 1,0,0,0x0D
 DEFB 0,30,5,0,0xEF,0x22,0x22,0xAF,0x0D
 DEFB 0,40,3,0,0xF3,'n',0x0D
 DEFB 0,50,14,0,0xF5,0xC0
TapFileEntryDigits:
 DEFB "00000",0x0E,0,0
TapFileEntryAddress:
 DEFW 0
 DEFB 0,0x0D
TapFileBodyChecksum:
 DEFB 0


